diff --git a/CMakeLists.txt b/CMakeLists.txt index f41fe3450fcd4f710e6925fd216683488751d7dd..0c999a6fc644ab7b16a9025723cf102ee6c0bb28 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -269,52 +269,10 @@ ENDIF() #File to compile SET( libringclient_LIB_SRCS #Data objects - src/call.cpp src/uri.cpp - src/account.cpp - src/person.cpp - src/contactmethod.cpp - src/numbercategory.cpp - src/macro.cpp - src/collectionextensioninterface.cpp - src/video/rate.cpp - src/video/device.cpp src/video/renderer.cpp - src/certificate.cpp - src/securityflaw.cpp - src/media/media.cpp - src/media/audio.cpp - src/media/video.cpp - src/media/text.cpp - src/media/file.cpp - src/media/recording.cpp - src/media/avrecording.cpp #Models - src/accountmodel.cpp - src/phonedirectorymodel.cpp - src/numbercategorymodel.cpp - src/macromodel.cpp - src/keyexchangemodel.cpp - src/securityevaluationmodel.cpp - src/personmodel.cpp - src/collectionmodel.cpp - src/collectionextensionmodel.cpp - src/collectionmanagerinterface.cpp - src/certificatemodel.cpp - src/chainoftrustmodel.cpp - src/video/devicemodel.cpp - src/video/sourcemodel.cpp - src/video/channel.cpp - src/video/resolution.cpp - src/video/configurationproxy.cpp - src/audio/alsapluginmodel.cpp - src/audio/inputdevicemodel.cpp - src/audio/managermodel.cpp - src/audio/outputdevicemodel.cpp - src/audio/ringtonedevicemodel.cpp - src/audio/settings.cpp - src/media/recordingmodel.cpp src/contactmodel.cpp src/newcallmodel.cpp src/newdevicemodel.cpp @@ -333,10 +291,6 @@ SET( libringclient_LIB_SRCS src/shmrenderer.cpp src/directrenderer.cpp - #Data collections - src/collectioninterface.cpp - src/collectioneditor.cpp - #Communication src/dbus/configurationmanager.cpp src/dbus/callmanager.cpp @@ -347,75 +301,23 @@ SET( libringclient_LIB_SRCS #Default interface implementations src/globalinstances.cpp src/pixmapmanipulatordefault.cpp - src/shortcutcreatordefault.cpp src/dbuserrorhandlerdefault.cpp #Other src/avmodel.cpp - src/hookmanager.cpp src/namedirectory.cpp - src/itembase.cpp - src/private/vcardutils.cpp - src/private/videorenderermanager.cpp - src/video/previewmanager.cpp - src/private/sortproxies.cpp - src/private/threadworker.cpp - src/mime.cpp src/smartinfohub.cpp - src/usage_statistics.cpp - - #Extension - src/extensions/securityevaluationextension.cpp ) # Public API SET( libringclient_LIB_HDRS - src/account.h - src/accountmodel.h - src/call.h - src/call.hpp - src/person.h - src/collectioninterface.h - src/collectioninterface.hpp - src/contactmethod.h - src/phonedirectorymodel.h - src/numbercategorymodel.h - src/keyexchangemodel.h - src/numbercategory.h - src/securityevaluationmodel.h - src/certificate.h - src/personmodel.h - src/collectionmodel.h - src/collectionextensionmodel.h - src/collectionextensionmodel.hpp - src/macromodel.h - src/hookmanager.h - src/namedirectory.h src/uri.h - src/macro.h - src/itembase.h - src/itembase.hpp - src/mime.h - src/collectionextensioninterface.h - src/collectionmanagerinterface.h - src/collectionmanagerinterface.hpp - src/certificatemodel.h - src/collectionmediator.h - src/collectionmediator.hpp - src/collectioneditor.h - src/collectioneditor.hpp - src/securityflaw.h - src/collectioncreationinterface.h - src/collectionconfigurationinterface.h - src/chainoftrustmodel.h src/globalinstances.h src/pixmapmanipulatordefault.h - src/shortcutcreatordefault.h src/dbuserrorhandlerdefault.h - src/itemdataroles.h src/smartinfohub.h - src/usage_statistics.h src/vcard.h + src/namedirectory.h src/shmrenderer.h src/directrenderer.h ) @@ -444,47 +346,12 @@ SET(libringclient_api_LIB_HDRS SET(libringclient_video_LIB_HDRS - src/video/device.h - src/video/devicemodel.h - src/video/sourcemodel.h src/video/renderer.h - src/video/resolution.h - src/video/channel.h - src/video/rate.h - src/video/previewmanager.h - src/video/configurationproxy.h #The renderer implementations are not exported on purpose ) -SET(libringclient_audio_LIB_HDRS - src/audio/alsapluginmodel.h - src/audio/inputdevicemodel.h - src/audio/managermodel.h - src/audio/outputdevicemodel.h - src/audio/ringtonedevicemodel.h - src/audio/settings.h -) - -SET(libringclient_extensions_LIB_HDRS - src/extensions/securityevaluationextension.h -) - -SET(libringclient_media_LIB_HDRS - src/media/media.h - src/media/audio.h - src/media/video.h - src/media/text.h - src/media/file.h - src/media/recording.h - src/media/avrecording.h - src/media/recordingmodel.h -) - SET(libringclient_interface_LIB_HDRS - src/interfaces/contactmethodselectori.h - src/interfaces/itemmodelstateserializeri.h src/interfaces/pixmapmanipulatori.h - src/interfaces/shortcutcreatori.h src/interfaces/dbuserrorhandleri.h ) @@ -582,24 +449,9 @@ ENDIF() # Manually wrap private files and interfaces SET(libringclient_PRIVATE_HDRS - src/private/call_p.h src/private/namedirectory_p.h - src/private/account_p.h - src/private/sortproxies.h - src/private/accountmodel_p.h - src/private/phonedirectorymodel_p.h - src/private/videorenderer_p.h - src/private/videodevice_p.h - src/private/collectionmodel_p.h - src/private/securityflaw_p.h - src/private/macromodel_p.h - src/private/person_p.h - src/collectioncreationinterface.h - src/private/securityevaluationmodel_p.h - src/collectionconfigurationinterface.h - src/private/imconversationmanagerprivate.h src/private/smartInfoHub_p.h - src/private/certificatemodel_p.h + src/private/videorenderer_p.h ) @@ -728,16 +580,6 @@ INSTALL( FILES ${libringclient_video_LIB_HDRS} COMPONENT Devel ) -INSTALL( FILES ${libringclient_audio_LIB_HDRS} - DESTINATION ${INCLUDE_INSTALL_DIR}/libringclient/audio - COMPONENT Devel -) - -INSTALL( FILES ${libringclient_media_LIB_HDRS} - DESTINATION ${INCLUDE_INSTALL_DIR}/libringclient/media - COMPONENT Devel -) - INSTALL( FILES ${libringclient_extensions_LIB_HDRS} DESTINATION ${INCLUDE_INSTALL_DIR}/libringclient/extensions COMPONENT Devel diff --git a/src/account.cpp b/src/account.cpp deleted file mode 100644 index d0b557f1e600faf81c9573542fa23858b6b415e2..0000000000000000000000000000000000000000 --- a/src/account.cpp +++ /dev/null @@ -1,2550 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -//Parent -#include "account.h" - -//Qt -#include <QtCore/QDebug> -#include <QtCore/QObject> -#include <QtCore/QString> -#include <QtCore/QMimeData> -#include <QtCore/QItemSelectionModel> -//Ring daemon -#include <account_const.h> -#include <presence_const.h> - -//Ring lib -#include "dbus/configurationmanager.h" -#include "dbus/callmanager.h" -#include "dbus/videomanager.h" -#include "dbus/presencemanager.h" -#include "globalinstances.h" -#include "certificate.h" -#include "certificatemodel.h" -#include "accountmodel.h" -#include "private/certificatemodel_p.h" -#include "private/account_p.h" -#include "private/accountmodel_p.h" -#include "person.h" -#include "contactmethod.h" -#include "phonedirectorymodel.h" -#include "uri.h" -#include "private/vcardutils.h" -#include "mime.h" -#include "namedirectory.h" -#include "securityevaluationmodel.h" -#include "private/securityevaluationmodel_p.h" -#include "extensions/securityevaluationextension.h" - -// define -#define TO_BOOL ?"true":"false" -#define IS_TRUE == "true" - - -#define AP &AccountPrivate -#define EA Account::EditAction -#define ES Account::EditState - -static EnumClassReordering<Account::EditAction> co = -{ EA::NOTHING, EA::EDIT , EA::RELOAD , EA::SAVE , EA::REMOVE , EA::MODIFY , EA::CANCEL }; -const Matrix2D<Account::EditState, Account::EditAction, account_function> AccountPrivate::stateMachineActionsOnState = { -{ES::READY ,{{co, { AP::nothing, AP::edit , AP::reload , AP::nothing, AP::remove , AP::modify , AP::nothing }}}}, -{ES::EDITING ,{{co, { AP::nothing, AP::nothing, AP::outdate, AP::nothing, AP::remove , AP::modify , AP::cancel }}}}, -{ES::OUTDATED ,{{co, { AP::nothing, AP::nothing, AP::nothing, AP::nothing, AP::remove , AP::reloadMod, AP::reload }}}}, -{ES::NEW ,{{co, { AP::nothing, AP::nothing, AP::nothing, AP::save , AP::remove , AP::nothing , AP::nothing }}}}, -{ES::MODIFIED_INCOMPLETE ,{{co, { AP::nothing, AP::nothing, AP::nothing, AP::save , AP::remove , AP::modify , AP::reload }}}}, -{ES::MODIFIED_COMPLETE ,{{co, { AP::nothing, AP::nothing, AP::nothing, AP::save , AP::remove , AP::modify , AP::reload }}}}, -{ES::REMOVED ,{{co, { AP::nothing, AP::nothing, AP::nothing, AP::nothing, AP::nothing, AP::nothing , AP::cancel }}}} -}; - -#undef ES -#undef EA -#undef AP - -//Host the current highest interal identifier. The internal id is used for some bitmasks -//when objects have a different status for each account -static uint p_sAutoIncrementId = 0; - -AccountPrivate::AccountPrivate(Account* acc) : QObject(acc),q_ptr(acc), -m_LastErrorCode(-1),m_VoiceMailCount(0),m_CurrentState(Account::EditState::READY), -m_pAccountNumber(nullptr),m_pKeyExchangeModel(nullptr),m_pSecurityEvaluationModel(nullptr), -m_pCaCert(nullptr),m_pTlsCert(nullptr),m_isLoaded(true),m_LastTransportCode(0),m_RegistrationState(Account::RegistrationState::UNREGISTERED), -m_UseDefaultPort(false),m_RemoteEnabledState(false), -m_pKnownCertificates(nullptr), -m_pBannedCertificates(nullptr), m_pAllowedCertificates(nullptr),m_InternalId(++p_sAutoIncrementId) -{ -} - -void AccountPrivate::changeState(Account::EditState state) { - const Account::EditState previous = m_CurrentState; - m_CurrentState = state; - - if (state != previous) - emit q_ptr->editStateChanged(state, previous); - - emit q_ptr->changed(q_ptr); -} - -///Constructors -Account::Account():ItemBase(&AccountModel::instance()),d_ptr(new AccountPrivate(this)) -{ -} - -///Build an account from it'id -Account* Account::buildExistingAccountFromId(const QByteArray& _accountId) -{ -// qDebug() << "Building an account from id: " << _accountId; - Account* a = new Account(); - a->d_ptr->m_AccountId = _accountId; - a->d_ptr->setObjectName(_accountId); - a->d_ptr->m_RemoteEnabledState = true; - - a->performAction(Account::EditAction::RELOAD); - - //If a placeholder exist for this account, upgrade it - if (auto place_holder = AccountModel::instance().findPlaceHolder(_accountId)) - place_holder->d_ptr->merge(a); - - //Load the pending trust requests - if (a->protocol() == Account::Protocol::RING) { - const VectorMapStringString& pending_tr {ConfigurationManager::instance().getTrustRequests(a->id())}; - for (const auto& tr_info : pending_tr) { - auto payload = tr_info[DRing::Account::TrustRequest::PAYLOAD].toUtf8(); - auto ringID = tr_info[DRing::Account::TrustRequest::FROM]; - auto timeReceived = tr_info[DRing::Account::TrustRequest::RECEIVED].toInt(); - - auto contactMethod = PhoneDirectoryModel::instance().getNumber(ringID, a); - auto person = VCardUtils::mapToPersonFromReceivedProfile(contactMethod, payload); - } - } - - // Load the contacts associated from the daemon and create the cms. - const auto account_contacts = static_cast<QVector<QMap<QString, QString>>>(ConfigurationManager::instance() - .getContacts(a->id().data())); - - if (a->protocol() == Account::Protocol::RING) { - for (auto contact_info : account_contacts) { - auto cm = PhoneDirectoryModel::instance().getNumber(contact_info["id"], a); - if (contact_info["banned"] IS_TRUE) { - } else { - cm->setConfirmed(contact_info["confirmed"] IS_TRUE); - a->d_ptr->m_NumbersFromDaemon << cm; - } - } - } - - //Load the tracked buddies - const VectorMapStringString subscriptions = PresenceManager::instance().getSubscriptions(a->id()); - foreach(auto subscription, subscriptions){ - ContactMethod* tracked_buddy = PhoneDirectoryModel::instance().getNumber(subscription[DRing::Presence::BUDDY_KEY], a); - bool tracked_buddy_present = subscription[DRing::Presence::STATUS_KEY].compare(DRing::Presence::ONLINE_KEY) == 0; - tracked_buddy->setTracked(true); - tracked_buddy->setPresent(tracked_buddy_present); - } - - return a; -} //buildExistingAccountFromId - -///Build an account from it's name / alias -Account* Account::buildNewAccountFromAlias(Account::Protocol proto, const QString& alias) -{ - qDebug() << "Building an account from alias: " << alias; - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - Account* a = new Account(); - a->setProtocol(proto); - a->d_ptr->m_hAccountDetails.clear(); - a->d_ptr->m_hAccountDetails[DRing::Account::ConfProperties::ENABLED] = "false"; - a->d_ptr->m_pAccountNumber = nullptr; - MapStringString tmp; - switch (proto) { - case Account::Protocol::SIP: - tmp = configurationManager.getAccountTemplate(DRing::Account::ProtocolNames::SIP); - break; - case Account::Protocol::RING: - tmp = configurationManager.getAccountTemplate(DRing::Account::ProtocolNames::RING); - break; - case Account::Protocol::COUNT__: - break; - } - QMutableMapIterator<QString, QString> iter(tmp); - while (iter.hasNext()) { - iter.next(); - a->d_ptr->m_hAccountDetails[iter.key()] = iter.value(); - } - - if (proto != Account::Protocol::RING) - { - a->setHostname(a->d_ptr->m_hAccountDetails[DRing::Account::ConfProperties::HOSTNAME]); - } - - a->d_ptr->setAccountProperty(DRing::Account::ConfProperties::ALIAS,alias); - a->d_ptr->m_RemoteEnabledState = a->isEnabled(); - //a->setObjectName(a->id()); - return a; -} - -///Destructor -Account::~Account() -{ - disconnect(); -} - -/***************************************************************************** - * * - * Slots * - * * - ****************************************************************************/ - -void AccountPrivate::slotPresentChanged(bool present) -{ - Q_UNUSED(present) - emit q_ptr->changed(q_ptr); -} - -void AccountPrivate::slotPresenceMessageChanged(const QString& message) -{ - Q_UNUSED(message) - emit q_ptr->changed(q_ptr); -} - -void AccountPrivate::slotUpdateCertificate() -{ - Certificate* cert = qobject_cast<Certificate*>(sender()); - if (cert) { - switch (cert->type()) { - case Certificate::Type::AUTHORITY: - if (accountDetail(DRing::Account::ConfProperties::TLS::CA_LIST_FILE) != cert->path()) - setAccountProperty(DRing::Account::ConfProperties::TLS::CA_LIST_FILE, cert->path()); - break; - case Certificate::Type::USER: - if (accountDetail(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE) != cert->path()) - setAccountProperty(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE, cert->path()); - break; - case Certificate::Type::PRIVATE_KEY: - if (accountDetail(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE) != cert->path()) - setAccountProperty(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE, cert->path()); - break; - case Certificate::Type::NONE: - case Certificate::Type::CALL: - break; - }; - } -} - -/***************************************************************************** - * * - * Getters * - * * - ****************************************************************************/ - -///IS this account new -bool Account::isNew() const -{ - return (d_ptr->m_AccountId == nullptr) || d_ptr->m_AccountId.isEmpty(); -} - -///Is this an IP2IP account -bool Account::isIp2ip() const -{ - return protocol() == Protocol::SIP && hostname().isEmpty(); -} - -///Get this account ID -const QByteArray Account::id() const -{ - if (isNew()) { - qDebug() << "Error : getting AccountId of a new account."; - return QByteArray(); //WARNING May explode - } - - return d_ptr->m_AccountId; -} - -///Get the device ID -QString Account::deviceId() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::RING_DEVICE_ID); -} - -///Get current state -const QString Account::toHumanStateName() const -{ - const QString s = d_ptr->m_hAccountDetails[DRing::Account::ConfProperties::Registration::STATUS]; - - //: Account state - static const QString ready = tr("Ready" ); - //: Account state - static const QString registered = tr("Registered" ); - //: Account state - static const QString notRegistered = tr("Not registered" ); - //: Account state - static const QString initializing = tr("Initializing" ); - //: Account state - static const QString trying = tr("Trying…" ); - //: Account state - static const QString error = tr("Error" ); - //: Account state - static const QString authenticationFailed = tr("Authentication failed" ); - //: Account state - static const QString networkUnreachable = tr("Network unreachable" ); - //: Account state - static const QString hostUnreachable = tr("Host unreachable" ); - //: Account state - static const QString stunConfigurationError = tr("STUN configuration error" ); - //: Account state - static const QString stunServerInvalid = tr("STUN server invalid" ); - //: Account state - static const QString serviceUnavailable = tr("Service unavailable" ); - //: Account state - static const QString notAcceptable = tr("Unacceptable" ); - //: Account state - static const QString invalid = tr("Invalid" ); - //: Account state - static const QString requestTimeout = tr("Request timeout" ); - - if(s == DRing::Account::States::READY ) - return ready ; - if(s == DRing::Account::States::REGISTERED ) - return registered ; - if(s == DRing::Account::States::INITIALIZING ) - return initializing ; - if(s == DRing::Account::States::UNREGISTERED ) - return notRegistered ; - if(s == DRing::Account::States::TRYING ) - return trying ; - if(s == DRing::Account::States::ERROR ) - return d_ptr->m_LastErrorMessage.isEmpty()?error:d_ptr->m_LastErrorMessage; - if(s == DRing::Account::States::ERROR_AUTH ) - return authenticationFailed ; - if(s == DRing::Account::States::ERROR_NETWORK ) - return networkUnreachable ; - if(s == DRing::Account::States::ERROR_HOST ) - return hostUnreachable ; - if(s == DRing::Account::States::ERROR_CONF_STUN ) - return stunConfigurationError ; - if(s == DRing::Account::States::ERROR_EXIST_STUN ) - return stunServerInvalid ; - if(s == DRing::Account::States::ERROR_SERVICE_UNAVAILABLE ) - return serviceUnavailable ; - if(s == DRing::Account::States::ERROR_NOT_ACCEPTABLE ) - return notAcceptable ; - if(s == DRing::Account::States::REQUEST_TIMEOUT ) - return requestTimeout ; - return invalid ; -} - -///Get an account detail -QString AccountPrivate::accountDetail(const QString& param) const -{ - if (!m_hAccountDetails.size()) { - qDebug() << "The account details is not set"; - return QString(); //May crash, but better than crashing now - } - if (m_hAccountDetails.find(param) != m_hAccountDetails.end()) { - return m_hAccountDetails[param]; - } - else if (m_hAccountDetails.count() > 0) { - if (param == DRing::Account::ConfProperties::ENABLED) //If an account is invalid, at least does not try to register it - return AccountPrivate::RegistrationEnabled::NO; - if (param == DRing::Account::ConfProperties::Registration::STATUS) { //If an account is new, then it is unregistered - return DRing::Account::States::UNREGISTERED; - } - static QHash<QString,bool> alreadyWarned; - if (!alreadyWarned[param]) { - alreadyWarned[param] = true; - qDebug() << "Account parameter \"" << param << "\" not found"; - } - return QString(); - } - else { - qDebug() << "Account details not found, there is " << m_hAccountDetails.count() << " details available"; - return QString(); - } -} //accountDetail - -///Get an account detail -QString Account::accountDetail(const QString& param) const -{ - return d_ptr->accountDetail(param); -} - -///Get the alias -const QString Account::alias() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ALIAS); -} - -///Return the model index of this item -QModelIndex Account::index() const -{ - //There is usually < 5 accounts, the loop may be faster than a hash for most users - for (int i=0;i < AccountModel::instance().size();i++) { - if (this == AccountModel::instance()[i]) { - return AccountModel::instance().index(i,0); - } - } - return QModelIndex(); -} - -///I -bool Account::isLoaded() const -{ - return d_ptr->m_isLoaded; -} - -KeyExchangeModel* Account::keyExchangeModel() const -{ - if (!d_ptr->m_pKeyExchangeModel) { - d_ptr->m_pKeyExchangeModel = new KeyExchangeModel(const_cast<Account*>(this)); - } - return d_ptr->m_pKeyExchangeModel; -} - -SecurityEvaluationModel* Account::securityEvaluationModel() const -{ - if (!d_ptr->m_pSecurityEvaluationModel) { - d_ptr->m_pSecurityEvaluationModel = new SecurityEvaluationModel(const_cast<Account*>(this)); - } - return d_ptr->m_pSecurityEvaluationModel; -} - -QAbstractItemModel* Account::knownCertificateModel() const -{ - if (!d_ptr->m_pKnownCertificates) { - d_ptr->m_pKnownCertificates = CertificateModel::instance().d_ptr->createKnownList(this); - } - - return d_ptr->m_pKnownCertificates; -} - -QAbstractItemModel* Account::bannedCertificatesModel() const -{ - if (protocol() != Account::Protocol::RING || isNew()) - return nullptr; - - if (!d_ptr->m_pBannedCertificates) { - d_ptr->m_pBannedCertificates = CertificateModel::instance().d_ptr->createBannedList(this); - } - - return d_ptr->m_pBannedCertificates; -} - -QAbstractItemModel* Account::allowedCertificatesModel() const -{ - if (protocol() != Account::Protocol::RING || isNew()) - return nullptr; - - if (!d_ptr->m_pAllowedCertificates) { - d_ptr->m_pAllowedCertificates = CertificateModel::instance().d_ptr->createAllowedList(this); - } - - return d_ptr->m_pAllowedCertificates; -} - -bool Account::isUsedForOutgogingCall() const -{ - return usageStats.haveCalled(); -} - -uint Account::totalCallCount() const -{ - return usageStats.totalCount(); -} - -uint Account::weekCallCount() const -{ - return usageStats.lastWeekCount(); -} - -uint Account::trimesterCallCount() const -{ - return usageStats.lastTrimCount(); -} - -time_t Account::lastUsed() const -{ - return usageStats.lastUsed(); -} - -/******************************************************************************* - * * - * Setters * - * * - ******************************************************************************/ - -void Account::setAlias(const QString& detail) -{ - const bool accChanged = detail != alias(); - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ALIAS,detail); - - if (accChanged) - emit aliasChanged(detail); -} - -///Return the account hostname -QString Account::hostname() const -{ - return d_ptr->m_HostName; -} - -///Return if the account is enabled -bool Account::isEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ENABLED) IS_TRUE; -} - -///Return if the account should auto answer -bool Account::isAutoAnswer() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::AUTOANSWER) IS_TRUE; -} - -//Return if the accounts needs to migrate -bool Account::needsMigration() const -{ - const MapStringString details = ConfigurationManager::instance().getVolatileAccountDetails(id()); - const QString status = details[DRing::Account::VolatileProperties::Registration::STATUS]; - return status == DRing::Account::States::ERROR_NEED_MIGRATION; -} - -/** - * return all ContactsMethod from @this account - * @return Account::ContactMethods a.k.a. QVector<ContactMethod*> - */ -Account::ContactMethods& -Account::getContacts() const -{ - return d_ptr->m_NumbersFromDaemon; -} - -///Return the account user name -QString Account::username() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::USERNAME); -} - -//Return the account registered name -QString Account::registeredName() const -{ - const MapStringString details = ConfigurationManager::instance().getVolatileAccountDetails(id()); - const QString registeredName = details[DRing::Account::VolatileProperties::REGISTERED_NAME]; - return registeredName; -} - -///Return the account mailbox address -QString Account::mailbox() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::MAILBOX); -} - -///Return the account mailbox address -QString Account::proxy() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ROUTE); -} - -///Return the name service URL -QString Account::nameServiceURL() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::RingNS::URI); -} - -QString Account::password() const -{ - switch (protocol()) { - case Account::Protocol::SIP: - break; - case Account::Protocol::RING: - return tlsPassword(); - case Account::Protocol::COUNT__: - break; - }; - return ""; -} - -///Return the account security fallback -bool Account::isSrtpRtpFallback() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::SRTP::RTP_FALLBACK) IS_TRUE; -} - -//Return if SRTP is enabled or not -bool Account::isSrtpEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::SRTP::ENABLED) IS_TRUE; -} - -///Return if the account is using a STUN server -bool Account::isSipStunEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::STUN::ENABLED) IS_TRUE; -} - -///Return the account STUN server -QString Account::sipStunServer() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::STUN::SERVER); -} - -///Return when the account expire (require renewal) -int Account::registrationExpire() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Registration::EXPIRE).toInt(); -} - -///Return if the published address is the same as the local one -bool Account::isPublishedSameAsLocal() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::PUBLISHED_SAMEAS_LOCAL) IS_TRUE; -} - -///Return the account published address -QString Account::publishedAddress() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::PUBLISHED_ADDRESS); -} - -///Return the account published port -int Account::publishedPort() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::PUBLISHED_PORT).toUInt(); -} - -///Return the account tls password -QString Account::tlsPassword() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::PASSWORD); -} - -///Return the account TLS port -int Account::bootstrapPort() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::DHT::PORT).toInt(); -} - -///Return the account TLS certificate authority list file -Certificate* Account::tlsCaListCertificate() const -{ - if (!d_ptr->m_pCaCert) { - const QString& path = d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::CA_LIST_FILE); - if (path.isEmpty()) - return nullptr; - d_ptr->m_pCaCert = CertificateModel::instance().getCertificateFromPath(path,Certificate::Type::AUTHORITY); - connect(d_ptr->m_pCaCert,SIGNAL(changed()),d_ptr.data(),SLOT(slotUpdateCertificate())); - } - return d_ptr->m_pCaCert; -} - -///Return the account TLS certificate -Certificate* Account::tlsCertificate() const -{ - if (!d_ptr->m_pTlsCert) { - const QString& path = d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE); - if (path.isEmpty()) - return nullptr; - d_ptr->m_pTlsCert = CertificateModel::instance().getCertificateFromPath(path,Certificate::Type::USER); - connect(d_ptr->m_pTlsCert,SIGNAL(changed()),d_ptr.data(),SLOT(slotUpdateCertificate())); - } - return d_ptr->m_pTlsCert; -} - -///Return the account private key -QString Account::tlsPrivateKey() const -{ - return tlsCertificate() ? tlsCertificate()->privateKeyPath() : QString(); -} - -///Return the account TLS server name -QString Account::tlsServerName() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::SERVER_NAME); -} - -///Return the account negotiation timeout in seconds -int Account::tlsNegotiationTimeoutSec() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::NEGOTIATION_TIMEOUT_SEC).toInt(); -} - -///Return the account TLS verify server -bool Account::isTlsVerifyServer() const -{ - return (d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::VERIFY_SERVER) IS_TRUE); -} - -///Return the account TLS verify client -bool Account::isTlsVerifyClient() const -{ - return (d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::VERIFY_CLIENT) IS_TRUE); -} - -///Return if it is required for the peer to have a certificate -bool Account::isTlsRequireClientCertificate() const -{ - return (d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::REQUIRE_CLIENT_CERTIFICATE) IS_TRUE); -} - -///Return the account TLS security is enabled -bool Account::isTlsEnabled() const -{ - return protocol() == Account::Protocol::RING || (d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::ENABLED) IS_TRUE); -} - -///Return if the ringtone are enabled -bool Account::isRingtoneEnabled() const -{ - return (d_ptr->accountDetail(DRing::Account::ConfProperties::Ringtone::ENABLED) IS_TRUE); -} - -///Return the account ringtone path -QString Account::ringtonePath() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Ringtone::PATH); -} - -///Get the last transport error message, this is used to debug why registration failed -QString Account::lastTransportErrorMessage() const -{ - return d_ptr->m_LastTransportMessage; -} - -///Return the account local port -int Account::localPort() const -{ - switch (protocol()) { - case Account::Protocol::SIP: - if (isTlsEnabled()) - return d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::LISTENER_PORT).toInt(); - else - return d_ptr->accountDetail(DRing::Account::ConfProperties::LOCAL_PORT).toInt(); - case Account::Protocol::RING: - return d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::LISTENER_PORT).toInt(); - case Account::Protocol::COUNT__: - break; - }; - return 0; -} - -///Return the number of voicemails -int Account::voiceMailCount() const -{ - return d_ptr->m_VoiceMailCount; -} - -///Return the account registration status -Account::RegistrationState Account::registrationState() const -{ - return d_ptr->m_RegistrationState; -} - -///Return the last account SIP registration status -QString Account::lastSipRegistrationStatus() const -{ - return d_ptr->m_LastSipRegistrationStatus; -} - -///Return the account type -Account::Protocol Account::protocol() const -{ - const QString str = d_ptr->accountDetail(DRing::Account::ConfProperties::TYPE); - - if (str.isEmpty() || str == DRing::Account::ProtocolNames::SIP) - return Account::Protocol::SIP; - else if (str == DRing::Account::ProtocolNames::RING) - return Account::Protocol::RING; - qDebug() << "Warning: unhandled protocol name" << str << ", defaulting to SIP"; - return Account::Protocol::SIP; -} - -///Return the contact method associated with this account -ContactMethod* Account::contactMethod() const -{ - return d_ptr->m_pAccountNumber; -} - -///Return the DTMF type -DtmfType Account::DTMFType() const -{ - QString type = d_ptr->accountDetail(DRing::Account::ConfProperties::DTMF_TYPE); - return (type == "overrtp" || type.isEmpty())? DtmfType::OverRtp:DtmfType::OverSip; -} - -QString Account::presenceMessage() const -{ - return d_ptr->m_pAccountNumber->presenceMessage(); -} - -bool Account::supportPresencePublish() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Presence::SUPPORT_PUBLISH) IS_TRUE; -} - -bool Account::supportPresenceSubscribe() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Presence::SUPPORT_SUBSCRIBE) IS_TRUE; -} - -bool Account::presenceEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Presence::ENABLED) IS_TRUE; -} - -bool Account::isVideoEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Video::ENABLED) IS_TRUE; -} - -int Account::videoPortMax() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Video::PORT_MAX).toInt(); -} - -int Account::videoPortMin() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Video::PORT_MIN).toInt(); -} - -int Account::audioPortMin() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Audio::PORT_MIN).toInt(); -} - -int Account::audioPortMax() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::Audio::PORT_MAX).toInt(); -} - -bool Account::isUpnpEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::UPNP_ENABLED) IS_TRUE; -} - -bool Account::hasCustomUserAgent() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::HAS_CUSTOM_USER_AGENT) IS_TRUE; -} - -QString Account::userAgent() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::USER_AGENT); -} - -bool Account::useDefaultPort() const -{ - return d_ptr->m_UseDefaultPort; -} - -QString Account::pushNotificationToken() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::PROXY_PUSH_TOKEN); -} - -bool Account::isProxyEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::PROXY_ENABLED) IS_TRUE; -} - -QString Account::proxyServer() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::PROXY_SERVER); -} - -bool Account::isTurnEnabled() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TURN::ENABLED) IS_TRUE; -} - -QString Account::turnServer() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TURN::SERVER); -} - -QString Account::turnServerUsername() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TURN::SERVER_UNAME); -} - -QString Account::turnServerPassword() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TURN::SERVER_PWD); -} - -QString Account::turnServerRealm() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::TURN::SERVER_REALM); -} - -bool Account::hasProxy() const -{ - return proxy().size(); -} - -QString Account::displayName() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::DISPLAYNAME); -} - -bool Account::archiveHasPassword() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ARCHIVE_HAS_PASSWORD) == "true"; -} - - -QString Account::archivePassword() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ARCHIVE_PASSWORD); -} - -QString Account::archivePin() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ARCHIVE_PIN); -} - -QString Account::archivePath() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ARCHIVE_PATH); -} - -bool Account::changePassword(const QString& currentPassword, const QString newPassword) const -{ - return ConfigurationManager::instance().changeAccountPassword(id(), currentPassword, newPassword); -} - -bool Account::allowIncomingFromUnknown() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::DHT::PUBLIC_IN_CALLS) IS_TRUE; -} - -bool Account::allowIncomingFromHistory() const -{ - if (protocol() != Account::Protocol::RING) - return false; - - return d_ptr->accountDetail(DRing::Account::ConfProperties::ALLOW_CERT_FROM_HISTORY) IS_TRUE; -} - -bool Account::allowIncomingFromContact() const -{ - if (protocol() != Account::Protocol::RING) - return false; - - return d_ptr->accountDetail(DRing::Account::ConfProperties::ALLOW_CERT_FROM_CONTACT) IS_TRUE; -} - -int Account::activeCallLimit() const -{ - return d_ptr->accountDetail(DRing::Account::ConfProperties::ACTIVE_CALL_LIMIT).toInt(); -} - -bool Account::hasActiveCallLimit() const -{ - return activeCallLimit() > -1; -} - -bool Account::exportOnRing(const QString& password) const -{ - return ConfigurationManager::instance().exportOnRing(id(), password); -} - -bool Account::exportToFile(const QString& destinationPath, const QString& password) const -{ - return ConfigurationManager::instance().exportToFile(id(), destinationPath, password); -} - -#define CAST(item) static_cast<int>(item) -QVariant Account::roleData(int role) const -{ - switch(role) { - //Generic - case Qt::DisplayRole: - case Qt::EditRole: - case CAST(Ring::Role::Name): - return alias(); - case Qt::CheckStateRole: - return QVariant(isEnabled() ? Qt::Checked : Qt::Unchecked); - case Qt::BackgroundRole: - return QVariant(); - case Qt::DecorationRole: - return QVariant(); - - //Specialized - case CAST(Account::Role::Alias): - return alias(); - case CAST(Account::Role::Proto): - return CAST(protocol()); - case CAST(Account::Role::Hostname): - return hostname(); - case CAST(Account::Role::Username): - return username(); - case CAST(Account::Role::Mailbox): - return mailbox(); - case CAST(Account::Role::Proxy): - return proxy(); -// case Password: -// return accountPassword(); - case CAST(Account::Role::TlsPassword): - return tlsPassword(); - case CAST(Account::Role::TlsCaListCertificate): - return tlsCaListCertificate()?tlsCaListCertificate()->path():QVariant(); - case CAST(Account::Role::TlsCertificate): - return tlsCertificate()?tlsCertificate()->path():QVariant(); - case CAST(Account::Role::TlsPrivateKey): - return tlsPrivateKey(); - case CAST(Account::Role::TlsServerName): - return tlsServerName(); - case CAST(Account::Role::SipStunServer): - return sipStunServer(); - case CAST(Account::Role::PublishedAddress): - return publishedAddress(); - case CAST(Account::Role::RingtonePath): - return ringtonePath(); - case CAST(Account::Role::RegistrationExpire): - return registrationExpire(); - case CAST(Account::Role::TlsNegotiationTimeoutSec): - return tlsNegotiationTimeoutSec(); - case CAST(Account::Role::LocalPort): - return localPort(); - case CAST(Account::Role::BootstrapPort): - return bootstrapPort(); - case CAST(Account::Role::PublishedPort): - return publishedPort(); - case CAST(Account::Role::Enabled): - return isEnabled(); - case CAST(Account::Role::AutoAnswer): - return isAutoAnswer(); - case CAST(Account::Role::TlsVerifyServer): - return isTlsVerifyServer(); - case CAST(Account::Role::TlsVerifyClient): - return isTlsVerifyClient(); - case CAST(Account::Role::TlsRequireClientCertificate): - return isTlsRequireClientCertificate(); - case CAST(Account::Role::TlsEnabled): - return isTlsEnabled(); - case CAST(Account::Role::SrtpRtpFallback): - return isSrtpRtpFallback(); - case CAST(Account::Role::SipStunEnabled): - return isSipStunEnabled(); - case CAST(Account::Role::PublishedSameAsLocal): - return isPublishedSameAsLocal(); - case CAST(Account::Role::RingtoneEnabled): - return isRingtoneEnabled(); - case CAST(Account::Role::dTMFType): - return DTMFType(); - case CAST(Account::Role::Id): - return id(); - case CAST(Ring::Role::Object): - case CAST(Account::Role::Object): { - QVariant var; - var.setValue(const_cast<Account*>(this)); - return var; - } - case CAST(Account::Role::TypeName): - return CAST(protocol()); - case CAST(Account::Role::RegistrationState): - return QVariant::fromValue(registrationState()); - case CAST(Account::Role::UsedForOutgogingCall): - return isUsedForOutgogingCall(); - case CAST(Account::Role::TotalCallCount): - return totalCallCount(); - case CAST(Account::Role::WeekCallCount): - return weekCallCount(); - case CAST(Account::Role::TrimesterCallCount): - return trimesterCallCount(); - case CAST(Ring::Role::LastUsed): - case CAST(Account::Role::LastUsed): - return (int)lastUsed(); - case CAST(Account::Role::UserAgent): - return userAgent(); - case CAST(Account::Role::Password): - return password(); - case CAST(Account::Role::SupportPresencePublish ): - return supportPresencePublish(); - case CAST(Account::Role::SupportPresenceSubscribe ): - return supportPresenceSubscribe(); - case CAST(Account::Role::PresenceEnabled ): - return presenceEnabled(); - case CAST(Account::Role::IsVideoEnabled ): - return isVideoEnabled(); - case CAST(Account::Role::VideoPortMax ): - return videoPortMax(); - case CAST(Account::Role::VideoPortMin ): - return videoPortMin(); - case CAST(Account::Role::AudioPortMin ): - return audioPortMin(); - case CAST(Account::Role::AudioPortMax ): - return audioPortMax(); - case CAST(Account::Role::IsUpnpEnabled ): - return isUpnpEnabled(); - case CAST(Account::Role::HasCustomUserAgent ): - return hasCustomUserAgent(); - case CAST(Account::Role::LastTransportErrorMessage): - return lastTransportErrorMessage(); - case CAST(Account::Role::PushnotiticationToken ): - return pushNotificationToken(); - case CAST(Account::Role::ProxyServer ): - return proxyServer(); - case CAST(Account::Role::ProxyEnabled ): - return isProxyEnabled(); - case CAST(Account::Role::TurnServer ): - return turnServer(); - case CAST(Account::Role::TurnServerEnabled ): - return isTurnEnabled(); - case CAST(Account::Role::TurnServerUsername ): - return turnServerUsername(); - case CAST(Account::Role::TurnServerPassword ): - return turnServerPassword(); - case CAST(Account::Role::TurnServerRealm ): - return turnServerRealm(); - case CAST(Account::Role::HasProxy ): - return hasProxy(); - case CAST(Account::Role::DisplayName ): - return displayName(); - case CAST(Account::Role::SrtpEnabled ): - return isSrtpEnabled(); - case CAST(Account::Role::KeyExchangeModel ): - return QVariant::fromValue(keyExchangeModel()); - case CAST(Account::Role::SecurityEvaluationModel ): - return QVariant::fromValue(securityEvaluationModel()); - case CAST(Account::Role::KnownCertificateModel ): - return QVariant::fromValue(knownCertificateModel()); - case CAST(Account::Role::BannedCertificatesModel ): - return QVariant::fromValue(bannedCertificatesModel()); - case CAST(Account::Role::AllowedCertificatesModel ): - return QVariant::fromValue(allowedCertificatesModel()); - case CAST(Account::Role::AllowIncomingFromHistory ): - return allowIncomingFromHistory(); - case CAST(Account::Role::AllowIncomingFromContact ): - return allowIncomingFromContact(); - case CAST(Account::Role::AllowIncomingFromUnknown ): - return allowIncomingFromUnknown(); - case CAST(Account::Role::ActiveCallLimit): - return activeCallLimit(); - case CAST(Account::Role::HasActiveCallLimit): - return hasActiveCallLimit(); - case CAST(Account::Role::SecurityLevel): - if (extension<SecurityEvaluationExtension>()) { - return QVariant::fromValue( - extension<SecurityEvaluationExtension>()->securityLevel(this) - ); - }; - break; - case CAST(Account::Role::SecurityLevelIcon): - if (extension<SecurityEvaluationExtension>()) { - return extension<SecurityEvaluationExtension>()->securityLevelIcon(this); - } - break; - case CAST(Account::Role::RegisteredName): - return registeredName(); - default: - return QVariant(); - } - return QVariant(); -} -#undef CAST - - -bool Account::supportScheme( URI::SchemeType type ) const -{ - switch(type) { - case URI::SchemeType::UNRECOGNIZED : - case URI::SchemeType::NONE : - if (protocol() == Account::Protocol::RING) - /* the URIs which are supported by accounts of type RING are well - * defined and should always be identified correctly, thus URIs - * which are not identified to be of a specific type cannot possibly - * be of type RING and thus should never be used to make a RING call - */ - return false; - return true; - break; - case URI::SchemeType::SIP : - case URI::SchemeType::SIPS : - if (protocol() == Account::Protocol::SIP) - return true; - break; - case URI::SchemeType::RING : - if (protocol() == Account::Protocol::RING) - return true; - break; - case URI::SchemeType::COUNT__: - break; - } - return false; -} - -bool Account::allowCertificate(Certificate* c) -{ - if (protocol() != Account::Protocol::RING) - return false; - - return CertificateModel::instance().d_ptr->allowCertificate(c, this); -} - -bool Account::banCertificate(Certificate* c) -{ - if (protocol() != Account::Protocol::RING) - return false; - - return CertificateModel::instance().d_ptr->banCertificate(c, this); -} - -bool Account::removeContact( const URI& uri ) -{ - if (uri.isEmpty()) - return false; - - ConfigurationManager::instance().removeContact(id(), uri, false); - - return true; -} - -bool Account::removeContact(const ContactMethod* c) -{ - if (!c) - return false; - - return removeContact(c->uri()); -} - -bool Account::removeContact( Certificate* c ) -{ - if ((!c) || (c->remoteId().isEmpty())) - return false; - - ConfigurationManager::instance().removeContact(id(), c->remoteId(), false); - return true; -} - -bool Account::addContact( const URI& uri ) -{ - if (uri.isEmpty()) - return false; - - ConfigurationManager::instance().addContact(id(), uri); - - return true; -} - -bool Account::addContact(const ContactMethod* c) -{ - if (!c) - return false; - - return addContact(c->uri()); -} - -bool Account::addContact( Certificate* c ) -{ - if ((!c) || (c->remoteId().isEmpty())) - return false; - - ConfigurationManager::instance().addContact(id(), c->remoteId()); - return true; -} - -bool Account::hasContact(ContactMethod* c ) -{ - auto contacts = getContacts(); - return contacts.indexOf(c) != -1; -} - -uint Account::internalId() const -{ - return d_ptr->m_InternalId; -} - - -/***************************************************************************** - * * - * Setters * - * * - ****************************************************************************/ - -///Set account details -void AccountPrivate::setAccountProperties(const QHash<QString,QString>& m) -{ - m_hAccountDetails.clear(); - m_hAccountDetails = m; - m_HostName = m[DRing::Account::ConfProperties::HOSTNAME]; -} - -///Set a specific detail -bool AccountPrivate::setAccountProperty(const QString& param, const QString& val) -{ - const QString buf = m_hAccountDetails[param]; - const bool accChanged = buf != val; - //Status can be changed regardless of the EditState - //TODO make this more generic for volatile properties - if (param == DRing::Account::ConfProperties::Registration::STATUS) { - m_hAccountDetails[param] = val; - if (accChanged) { - emit q_ptr->changed(q_ptr); - emit q_ptr->propertyChanged(q_ptr,param,val,buf); - } - } - else if (accChanged) { - - m_hAccountDetails[param] = val; - emit q_ptr->changed(q_ptr); - emit q_ptr->propertyChanged(q_ptr,param,val,buf); - - q_ptr->performAction(Account::EditAction::MODIFY); - } - return m_CurrentState == Account::EditState::MODIFIED_COMPLETE - || m_CurrentState == Account::EditState::MODIFIED_INCOMPLETE - || m_CurrentState == Account::EditState::NEW; -} - -bool Account::setAccountProperty(const QString& param, const QString& val) -{ - return d_ptr->setAccountProperty(param, val); -} - -///Set the account id -void Account::setId(const QByteArray& id) -{ - if (! isNew()) - qDebug() << "Error : setting AccountId of an existing account" << d_ptr->m_AccountId; - d_ptr->m_AccountId = id; -} - -///Set the account type, SIP or RING -void Account::setProtocol(Account::Protocol proto) -{ - //TODO prevent this if the protocol has been saved - switch (proto) { - case Account::Protocol::SIP: - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TYPE ,DRing::Account::ProtocolNames::SIP ); - break; - case Account::Protocol::RING: - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TYPE ,DRing::Account::ProtocolNames::RING); - break; - case Account::Protocol::COUNT__: - break; - }; -} - -///The set account hostname, it can be an hostname or an IP address -void Account::setHostname(const QString& detail) -{ - if (d_ptr->m_HostName != detail) { - d_ptr->m_HostName = detail; - d_ptr->setAccountProperty(DRing::Account::ConfProperties::HOSTNAME, detail); - } -} - - -///Set the account registeredName -bool Account::registerName(const QString& password, const QString& name) const -{ - return NameDirectory::instance().registerName(this, password, name); -} - -//Lookup a name -bool Account::lookupName(const QString& name) const -{ - return NameDirectory::instance().lookupName(this, QString(), name); -} - -//Lookup an address -bool Account::lookupAddress(const QString& address) const -{ - return NameDirectory::instance().lookupAddress(this, QString(), address); -} - -///Set the account username, everything is valid, some might be rejected by the PBX server -void Account::setUsername(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::USERNAME, detail); - switch (protocol()) { - case Account::Protocol::RING: - case Account::Protocol::COUNT__: - //nothing to do - break; - case Account::Protocol::SIP: - break; - }; -} - -///Set the account mailbox, usually a number, but can be anything -void Account::setMailbox(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::MAILBOX, detail); -} - -///Set the account mailbox, usually a number, but can be anything -void Account::setProxy(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ROUTE, detail); -} - -//Set the name service URL -void Account::setNameServiceURL(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::RingNS::URI, detail); -} - -///Set the main password -void Account::setPassword(const QString& detail) -{ - switch (protocol()) { - case Account::Protocol::SIP: - break; - case Account::Protocol::RING: - setTlsPassword(detail); - break; - case Account::Protocol::COUNT__: - break; - }; -} - -///Set the TLS (encryption) password -void Account::setTlsPassword(const QString& detail) -{ - auto cert = tlsCertificate(); - if (!cert) - return; - cert->setPrivateKeyPassword(detail); - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::PASSWORD, detail); - d_ptr->regenSecurityValidation(); -} - -///Set the certificate authority list file -void Account::setTlsCaListCertificate(const QString& path) -{ - Certificate* cert = CertificateModel::instance().getCertificateFromPath(path); - setTlsCaListCertificate(cert); -} - -///Set the certificate -void Account::setTlsCertificate(const QString& path) -{ - Certificate* cert = CertificateModel::instance().getCertificateFromPath(path); - setTlsCertificate(cert); -} - -///Set the private key -void Account::setTlsPrivateKey(const QString& path) -{ - auto cert = tlsCertificate(); - if (!cert) - return; - - cert->setPrivateKeyPath(path); - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE, cert?path:QString()); - d_ptr->regenSecurityValidation(); -} - -///Set the certificate authority list file -void Account::setTlsCaListCertificate(Certificate* cert) -{ - //FIXME it can be a list of multiple certificates - //this code currently only handle the case where is there is exactly one - - cert->setRequireStrictPermission(false); - - //All calls from the same top level CA are always accepted - allowCertificate(cert); - - d_ptr->m_pCaCert = cert; - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::CA_LIST_FILE, cert?cert->path():QString()); - d_ptr->regenSecurityValidation(); - - if (d_ptr->m_cTlsCaCert) - disconnect(d_ptr->m_cTlsCaCert); - - if (cert) { - d_ptr->m_cTlsCaCert = connect(cert, &Certificate::changed,[this]() { - d_ptr->regenSecurityValidation(); - }); - } - -} - -///Set the certificate -void Account::setTlsCertificate(Certificate* cert) -{ - //The private key will be required for this certificate - cert->setRequirePrivateKey(true); - - d_ptr->m_pTlsCert = cert; - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE, cert?cert->path():QString()); - d_ptr->regenSecurityValidation(); -} - -///Set the TLS server -void Account::setTlsServerName(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::SERVER_NAME, detail); - d_ptr->regenSecurityValidation(); -} - -///Set the stun server -void Account::setSipStunServer(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::STUN::SERVER, detail); -} - -///Set the published address -void Account::setPublishedAddress(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::PUBLISHED_ADDRESS, detail); -} - -///Set the ringtone path, it have to be a valid absolute path -void Account::setRingtonePath(const QString& detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Ringtone::PATH, detail); -} - -///Set the number of voice mails -void Account::setVoiceMailCount(int count) -{ - d_ptr->m_VoiceMailCount = count; -} - -///Set the account timeout, it will be renegotiated when that timeout occur -void Account::setRegistrationExpire(int detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Registration::EXPIRE, QString::number(detail)); -} - -///Set TLS negotiation timeout in second -void Account::setTlsNegotiationTimeoutSec(int detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::NEGOTIATION_TIMEOUT_SEC, QString::number(detail)); - d_ptr->regenSecurityValidation(); -} - -///Set the local port for SIP/RING communications -void Account::setLocalPort(unsigned short detail) -{ - switch (protocol()) { - case Account::Protocol::SIP: - if (isTlsEnabled()) - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::LISTENER_PORT, QString::number(detail)); - else - d_ptr->setAccountProperty(DRing::Account::ConfProperties::LOCAL_PORT, QString::number(detail)); - case Account::Protocol::RING: - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::LISTENER_PORT, QString::number(detail)); - break; - case Account::Protocol::COUNT__: - break; - }; -} - -///Set the TLS listener port (0-2^16) -void Account::setBootstrapPort(unsigned short detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::DHT::PORT, QString::number(detail)); -} - -///Set the published port (0-2^16) -void Account::setPublishedPort(unsigned short detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::PUBLISHED_PORT, QString::number(detail)); -} - -///Set if the account is enabled or not -void Account::setEnabled(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ENABLED, (detail)TO_BOOL); -} - -///Set if the account should auto answer -void Account::setAutoAnswer(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::AUTOANSWER, (detail)TO_BOOL); -} - -///Set the TLS verification server -void Account::setTlsVerifyServer(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::VERIFY_SERVER, (detail)TO_BOOL); - d_ptr->regenSecurityValidation(); -} - -///Set the TLS verification client -void Account::setTlsVerifyClient(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::VERIFY_CLIENT, (detail)TO_BOOL); - d_ptr->regenSecurityValidation(); -} - -///Set if the peer need to be providing a certificate -void Account::setTlsRequireClientCertificate(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::REQUIRE_CLIENT_CERTIFICATE ,(detail)TO_BOOL); - d_ptr->regenSecurityValidation(); -} - -///Set if the security settings are enabled -void Account::setTlsEnabled(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::ENABLED ,(detail)TO_BOOL); - d_ptr->regenSecurityValidation(); -} - -void Account::setSrtpRtpFallback(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::SRTP::RTP_FALLBACK, (detail)TO_BOOL); - d_ptr->regenSecurityValidation(); -} - -void Account::setSrtpEnabled(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::SRTP::ENABLED, (detail)TO_BOOL); - d_ptr->regenSecurityValidation(); -} - -void Account::setSipStunEnabled(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::STUN::ENABLED, (detail)TO_BOOL); -} - -/** - * Set if the published address is the same as the local IP address - * @see Account::setPublishedAddress - * @see Account::publishedAddress - */ -void Account::setPublishedSameAsLocal(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::PUBLISHED_SAMEAS_LOCAL, (detail)TO_BOOL); -} - -///Set if custom ringtone are enabled -void Account::setRingtoneEnabled(bool detail) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Ringtone::ENABLED, (detail)TO_BOOL); -} - -/** - * Set if the account broadcast its presence data - * - * @note This only works when the account support presence - * @see Account::supportPresencePublish() - */ -void Account::setPresenceEnabled(bool enable) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Presence::ENABLED, (enable)TO_BOOL); - emit presenceEnabledChanged(enable); -} - -///Use video by default when available -void Account::setVideoEnabled(bool enable) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Video::ENABLED, (enable)TO_BOOL); -} - -/**Set the maximum audio port - * This can be used when some routers without UPnP support open a narrow range - * of ports to allow the stream to go through. - */ -void Account::setAudioPortMax(int port ) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Audio::PORT_MAX, QString::number(port)); -} - -/**Set the minimum audio port - * This can be used when some routers without UPnP support open a narrow range - * of ports to allow the stream to go through. - */ -void Account::setAudioPortMin(int port ) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Audio::PORT_MIN, QString::number(port)); -} - -/**Set the maximum video port - * This can be used when some routers without UPnP support open a narrow range - * of ports to allow the stream to go through. - */ -void Account::setVideoPortMax(int port ) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Video::PORT_MAX, QString::number(port)); -} - -/**Set the minimum video port - * This can be used when some routers without UPnP support open a narrow range - * of ports to allow the stream to go through. - */ -void Account::setVideoPortMin(int port ) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::Video::PORT_MIN, QString::number(port)); -} - -void Account::setUpnpEnabled(bool enable) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::UPNP_ENABLED, (enable)TO_BOOL); -} - -void Account::setHasCustomUserAgent(bool enable) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::HAS_CUSTOM_USER_AGENT, (enable)TO_BOOL); -} - -///TODO implement the "use default" logic correctly -/**Set the user agent - * If the string is unchanged, the daemon should upgrade it automatically - */ -void Account::setUserAgent(const QString& agent) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::USER_AGENT, agent); -} - -void Account::setUseDefaultPort(bool value) -{ - if (value) { - switch (protocol()) { - case Account::Protocol::SIP: - setLocalPort(5060); //FIXME check is TLS is used - break; - case Account::Protocol::RING: - setLocalPort(5061); - break; - case Account::Protocol::COUNT__: - break; - }; - } - d_ptr->m_UseDefaultPort = value; -} - -void Account::setProxyEnabled(bool value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::PROXY_ENABLED, (value)TO_BOOL); -} - -void Account::setProxyServer(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::PROXY_SERVER, (value)); -} - -void Account::setPushNotificationToken(const QString& token) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::PROXY_PUSH_TOKEN, (token)); -} - -void Account::setTurnEnabled(bool value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TURN::ENABLED, (value)TO_BOOL); -} - -void Account::setTurnServer(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER, value); -} - -void Account::setTurnServerUsername(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER_UNAME, value); -} - -void Account::setTurnServerPassword(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER_PWD, value); -} - -void Account::setTurnServerRealm(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER_REALM, value); -} - -void Account::setDisplayName(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::DISPLAYNAME, value); -} - -void Account::setArchivePassword(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ARCHIVE_PASSWORD, value); -} - -void Account::setArchivePin(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ARCHIVE_PIN, value); -} - -void Account::setArchivePath(const QString& value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ARCHIVE_PATH, value); -} - -void Account::setAllowIncomingFromUnknown(bool value) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::DHT::PUBLIC_IN_CALLS, (value)TO_BOOL); -} - -void Account::setAllowIncomingFromHistory(bool value) -{ - if (protocol() != Account::Protocol::RING) - return; - - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ALLOW_CERT_FROM_HISTORY, value TO_BOOL); - performAction(Account::EditAction::MODIFY); -} - -void Account::setAllowIncomingFromContact(bool value) -{ - if (protocol() != Account::Protocol::RING) - return; - - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ALLOW_CERT_FROM_CONTACT, value TO_BOOL); - performAction(Account::EditAction::MODIFY); -} - -void Account::setActiveCallLimit(int value ) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::ACTIVE_CALL_LIMIT, QString::number(value)); -} - -void Account::setHasActiveCallLimit(bool value ) -{ - if ((!value) && activeCallLimit() != -1) - return; - - setActiveCallLimit(value?1:-1); -} - -///Set the DTMF type -void Account::setDTMFType(DtmfType type) -{ - d_ptr->setAccountProperty(DRing::Account::ConfProperties::DTMF_TYPE,(type==OverRtp)?"overrtp":"oversip"); -} - -void Account::setLastSipRegistrationStatus(const QString& value ) -{ - d_ptr->m_LastSipRegistrationStatus = value; -} - -void Account::setLastTransportCode(int value) -{ - d_ptr->m_LastTransportCode = value; -} - -void Account::setLastTransportMessage(const QString& value) -{ - d_ptr->m_LastTransportMessage = value; -} - -void Account::setRegistrationState(const RegistrationState& value) -{ - d_ptr->m_RegistrationState = value; -} - -#define CAST(item) static_cast<int>(item) -///Proxy for AccountModel::setData -void Account::setRoleData(int role, const QVariant& value) -{ - switch(role) { - case CAST(Account::Role::Alias): - setAlias(value.toString()); - break; - case CAST(Account::Role::Proto): { - const int proto = value.toInt(); - setProtocol((proto>=0&&proto<=1)?static_cast<Account::Protocol>(proto):Account::Protocol::SIP); - break; - } - case CAST(Account::Role::Hostname): - setHostname(value.toString()); - break; - case CAST(Account::Role::Username): - setUsername(value.toString()); - break; - case CAST(Account::Role::Mailbox): - setMailbox(value.toString()); - break; - case CAST(Account::Role::Proxy): - setProxy(value.toString()); - break; -// case Password: -// accountPassword(); - case CAST(Account::Role::TlsPassword): - setTlsPassword(value.toString()); - break; - case CAST(Account::Role::TlsCaListCertificate): { - setTlsCaListCertificate(value.toString()); - break; - } - case CAST(Account::Role::TlsCertificate): { - setTlsCertificate(value.toString()); - } - break; - case CAST(Account::Role::TlsServerName): - setTlsServerName(value.toString()); - break; - case CAST(Account::Role::SipStunServer): - setSipStunServer(value.toString()); - break; - case CAST(Account::Role::PublishedAddress): - setPublishedAddress(value.toString()); - break; - case CAST(Account::Role::RingtonePath): - setRingtonePath(value.toString()); - break; - case CAST(Account::Role::RegistrationExpire): - setRegistrationExpire(value.toInt()); - break; - case CAST(Account::Role::TlsNegotiationTimeoutSec): - setTlsNegotiationTimeoutSec(value.toInt()); - break; - case CAST(Account::Role::LocalPort): - setLocalPort(value.toInt()); - break; - case CAST(Account::Role::BootstrapPort): - setBootstrapPort(value.toInt()); - break; - case CAST(Account::Role::PublishedPort): - setPublishedPort(value.toInt()); - break; - case CAST(Account::Role::Enabled): - setEnabled(value.toBool()); - break; - case CAST(Account::Role::AutoAnswer): - setAutoAnswer(value.toBool()); - break; - case CAST(Account::Role::TlsVerifyServer): - setTlsVerifyServer(value.toBool()); - break; - case CAST(Account::Role::TlsVerifyClient): - setTlsVerifyClient(value.toBool()); - break; - case CAST(Account::Role::TlsRequireClientCertificate): - setTlsRequireClientCertificate(value.toBool()); - break; - case CAST(Account::Role::TlsEnabled): - setTlsEnabled(value.toBool()); - break; - case CAST(Account::Role::SrtpRtpFallback): - setSrtpRtpFallback(value.toBool()); - break; - case CAST(Account::Role::SipStunEnabled): - setSipStunEnabled(value.toBool()); - break; - case CAST(Account::Role::PublishedSameAsLocal): - setPublishedSameAsLocal(value.toBool()); - break; - case CAST(Account::Role::RingtoneEnabled): - setRingtoneEnabled(value.toBool()); - break; - case CAST(Account::Role::dTMFType): - setDTMFType((DtmfType)value.toInt()); - break; - case CAST(Account::Role::Id): - setId(value.toByteArray()); - break; - case CAST(Account::Role::UserAgent): - setUserAgent(value.toString()); - break; - case CAST(Account::Role::Password): - setPassword(value.toString()); - break; - case CAST(Account::Role::SupportPresencePublish ): - break; - case CAST(Account::Role::SupportPresenceSubscribe ): - break; - case CAST(Account::Role::PresenceEnabled ): - setPresenceEnabled(value.toBool()); - break; - case CAST(Account::Role::IsVideoEnabled ): - setVideoEnabled(value.toBool()); - break; - case CAST(Account::Role::VideoPortMax ): - setVideoPortMax(value.toInt()); - break; - case CAST(Account::Role::VideoPortMin ): - setVideoPortMin(value.toInt()); - break; - case CAST(Account::Role::AudioPortMin ): - setAudioPortMin(value.toInt()); - break; - case CAST(Account::Role::AudioPortMax ): - setAudioPortMax(value.toInt()); - break; - case CAST(Account::Role::IsUpnpEnabled ): - setUpnpEnabled(value.toBool()); - break; - case CAST(Account::Role::HasCustomUserAgent ): - setHasCustomUserAgent(value.toBool()); - break; - case CAST(Account::Role::LastTransportErrorCode ): - break; - case CAST(Account::Role::LastTransportErrorMessage): - break; - case CAST(Account::Role::TurnServer ): - setTurnServer(value.toString()); - break; - case CAST(Account::Role::DisplayName ): - setDisplayName(value.toString()); - break; - case CAST(Account::Role::SrtpEnabled ): - setSrtpEnabled(value.toBool()); - break; - case CAST(Account::Role::KeyExchangeModel ): - case CAST(Account::Role::StatusModel ): - case CAST(Account::Role::SecurityEvaluationModel ): - case CAST(Account::Role::KnownCertificateModel ): - case CAST(Account::Role::BannedCertificatesModel ): - case CAST(Account::Role::AllowedCertificatesModel ): - break; - case CAST(Account::Role::AllowIncomingFromHistory ): - setAllowIncomingFromHistory(value.toBool()); - break; - case CAST(Account::Role::AllowIncomingFromContact ): - setAllowIncomingFromContact(value.toBool()); - break; - case CAST(Account::Role::AllowIncomingFromUnknown ): - setAllowIncomingFromUnknown(value.toBool()); - break; - case CAST(Account::Role::ActiveCallLimit): - return setActiveCallLimit(value.toInt()); - break; - case CAST(Account::Role::HasActiveCallLimit): - return setHasActiveCallLimit(value.toBool()); - break; - //Read-only - case CAST(Account::Role::SecurityLevel): - case CAST(Account::Role::SecurityLevelIcon): - break; - case CAST(Account::Role::TurnServerPassword): - setTurnServerPassword(value.toString()); - break; - case CAST(Account::Role::TurnServerRealm): - setTurnServerRealm(value.toString()); - break; - case CAST(Account::Role::TurnServerUsername): - setTurnServerUsername(value.toString()); - break; - case CAST(Account::Role::TurnServerEnabled): - setTurnEnabled(value.toBool()); - break; - case CAST(Account::Role::ProxyEnabled): - setProxyEnabled(value.toBool()); - break; - case CAST(Account::Role::ProxyServer): - setProxy(value.toString()); - break; - } -} -#undef CAST - - -/***************************************************************************** - * * - * Mutator * - * * - ****************************************************************************/ - -void AccountPrivate::performAction(const Account::EditAction action) -{ - (this->*(stateMachineActionsOnState[m_CurrentState][action]))(); -} - -/// anAccount << Call::EditAction::SAVE -Account* Account::operator<<(Account::EditAction& action) -{ - performAction(action); - return this; -} - -Account* operator<<(Account* a, Account::EditAction action) -{ - return (!a)?nullptr : (*a) << action; -} - -///Change the current edition state -bool Account::performAction(const Account::EditAction action) -{ - Account::EditState curState = d_ptr->m_CurrentState; - d_ptr->performAction(action); - return curState != d_ptr->m_CurrentState; -} - -///Get the current account edition state -Account::EditState Account::editState() const -{ - return d_ptr->m_CurrentState; -} - -/** - * This method can be used to query if a field is available or not in current - * context. This could be extended over time. For now, it only handle the fields - * related to SDES. - * - * @todo Support of the private key password is necessary - * - * @param role An SDES related Account::Role - * @return if the field is available in the current context - */ -Account::RoleState Account::roleState(Account::Role role) const -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wswitch-enum" - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wswitch" - - //Hide unsupported fields by protocol - switch(protocol()) { - case Account::Protocol::RING: - switch(role) { - case Account::Role::Password : - case Account::Role::RegistrationExpire: - case Account::Role::Mailbox : - case Account::Role::UserAgent : - case Account::Role::HasCustomUserAgent: - case Account::Role::HasProxy : - case Account::Role::Proxy : - case Account::Role::DisplayName : - return Account::RoleState::UNAVAILABLE; - case Account::Role::Username : - case Account::Role::TlsCaListCertificate : - case Account::Role::TlsCertificate : - case Account::Role::SrtpEnabled : - case Account::Role::TlsEnabled : - return Account::RoleState::READ_ONLY; - default: - break; - } - - // The registered name cannot be changed once the account is created - if (!isNew() && role == Account::Role::RegisteredName) - return Account::RoleState::READ_ONLY; - - break; - case Account::Protocol::SIP : - switch(role) { - case Account::Role::PresenceEnabled: - return supportPresenceSubscribe() || supportPresencePublish() ? - Account::RoleState::READ_WRITE : Account::RoleState::UNAVAILABLE; - } - [[clang::fallthrough]]; - case Account::Protocol::COUNT__ : - switch(role) { - case Account::Role::BannedCertificatesModel : - case Account::Role::AllowedCertificatesModel: - case Account::Role::AllowIncomingFromHistory: - case Account::Role::AllowIncomingFromContact: - case Account::Role::AllowIncomingFromUnknown: - case Account::Role::RegisteredName : - return Account::RoleState::UNAVAILABLE; - } - break; - } - - //Supported security fields - enum class Fields { - SDES_FALLBACK_RTP , - COUNT__ - }; - - //Mapping between the roles and the fields - Fields f = Fields::COUNT__; - switch(role) { - case Account::Role::SrtpRtpFallback : - f = Fields::SDES_FALLBACK_RTP ; - break; - } - #pragma GCC diagnostic pop - #pragma GCC diagnostic pop - - //The field is not possible to disable - if (f == Fields::COUNT__) - return Account::RoleState::READ_WRITE; - - constexpr static const Account::RoleState rw = Account::RoleState::READ_WRITE ; - constexpr static const Account::RoleState un = Account::RoleState::UNAVAILABLE; - - //Matrix used to define if a field is enabled - static const Matrix2D<KeyExchangeModel::Type, Fields, Account::RoleState> - enabledFields={{ - /* ______________________> SDES_FALLBACK_RTP */ - /* / */ - /* \/ */ - /*Type::SDES*/ {{rw}}, - /*Type::NONE*/ {{un}}, - }}; - - const QModelIndex idx = keyExchangeModel()->selectionModel()->currentIndex(); - - if (!idx.isValid()) - return Account::RoleState::UNAVAILABLE; - - const KeyExchangeModel::Type type = qvariant_cast<KeyExchangeModel::Type>( - idx.data(static_cast<int>(KeyExchangeModel::Role::TYPE)) - ); - - return enabledFields[type][f]; -} - -/** - * Get the **current** status of the role based on its content. ::roleState - * check the field state based on protocol and context with ::roleStatus check - * the content. - */ -Account::RoleStatus Account::roleStatus(Account::Role role) const -{ - //The validations are currently performed by the state machine - return d_ptr->m_hRoleStatus[(int)role]; -} - -/**Update the account - * @return if the state changed - */ -bool AccountPrivate::updateState() -{ - if(! q_ptr->isNew()) { - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const MapStringString details = configurationManager.getVolatileAccountDetails(q_ptr->id()); - const QString status = details[DRing::Account::VolatileProperties::Registration::STATUS]; - const Account::RegistrationState cst = q_ptr->registrationState(); - const Account::RegistrationState st = Account::fromDaemonName(status); - - setAccountProperty(DRing::Account::ConfProperties::Registration::STATUS, status); //Update -internal- object state - m_RegistrationState = st; - - if (st != cst) - emit q_ptr->stateChanged(q_ptr->registrationState()); - - return st == cst; - } - return true; -} - -bool Account::updateState() -{ - return d_ptr->updateState(); -} - -///Save the current account to the daemon -void AccountPrivate::save() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - if (q_ptr->isNew()) { - MapStringString details; - QMutableHashIterator<QString,QString> iter(m_hAccountDetails); - - while (iter.hasNext()) { - iter.next(); - details[iter.key()] = iter.value(); - } - - //Clear the password - q_ptr->setArchivePassword(""); - - const QString currentId = configurationManager.addAccount(details); - - q_ptr->setId(currentId.toLatin1()); - } //New account - else { //Existing account - MapStringString tmp; - QMutableHashIterator<QString,QString> iter(m_hAccountDetails); - - while (iter.hasNext()) { - iter.next(); - tmp[iter.key()] = iter.value(); - } - configurationManager.setAccountDetails(q_ptr->id(), tmp); - if (m_RemoteEnabledState != q_ptr->isEnabled()) { - m_RemoteEnabledState = q_ptr->isEnabled(); - emit q_ptr->enabled(m_RemoteEnabledState); - } - } - - if (!q_ptr->id().isEmpty()) { - Account* acc = AccountModel::instance().getById(q_ptr->id()); - if (acc != q_ptr) { - qDebug() << "Adding the new account to the account list (" << q_ptr->id() << ")"; - AccountModel::instance().add(q_ptr); - } - - q_ptr->performAction(Account::EditAction::RELOAD); - updateState(); - - changeState(Account::EditState::READY); - } - - emit q_ptr->changed(q_ptr); -} - -///sync with the daemon, this need to be done manually to prevent reloading the account while it is being edited -void AccountPrivate::reload() -{ - if (!q_ptr->isNew()) { - if (m_hAccountDetails.size()) - qDebug() << "Reloading" << q_ptr->id() << q_ptr->alias(); - else - qDebug() << "Loading" << q_ptr->id(); - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - QMap<QString,QString> aDetails = configurationManager.getAccountDetails(q_ptr->id()); - - if (!aDetails.count()) { - qDebug() << "Account not found"; - } - else { - m_hAccountDetails.clear(); - //In case not all elements match, it is better to do a "merge" - QMutableMapIterator<QString, QString> iter(aDetails); - while (iter.hasNext()) { - iter.next(); - m_hAccountDetails[iter.key()] = iter.value(); - } - - //Manually re-set elements that need extra business logic or caching - q_ptr->setHostname(m_hAccountDetails[DRing::Account::ConfProperties::HOSTNAME]); - - const QString ca (m_hAccountDetails[DRing::Account::ConfProperties::TLS::CA_LIST_FILE ]); - const QString cert(m_hAccountDetails[DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE]); - const QString key (m_hAccountDetails[DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE]); - const QString pass(m_hAccountDetails[DRing::Account::ConfProperties::TLS::PASSWORD]); - - if (!ca.isEmpty()) - q_ptr->setTlsCaListCertificate(ca); - - // Set the pvk file and password only if there is a certificate - if (!cert.isEmpty()) { - q_ptr->setTlsCertificate(cert); - if (!key.isEmpty()) { - q_ptr->setTlsPrivateKey(key); - if (!pass.isEmpty()) - q_ptr->setTlsPassword(pass); - } - } - - m_RemoteEnabledState = q_ptr->isEnabled(); - } - - changeState(Account::EditState::READY); - - //TODO port this to the URI class helpers, this doesn't cover all corner cases - const QString currentUri = QString("%1@%2").arg(q_ptr->username()).arg(m_HostName); - - if (!m_pAccountNumber || (m_pAccountNumber && m_pAccountNumber->uri() != currentUri)) { - if (m_pAccountNumber) { - disconnect(m_pAccountNumber,SIGNAL(presenceMessageChanged(QString)),this,SLOT(slotPresenceMessageChanged(QString))); - disconnect(m_pAccountNumber,SIGNAL(presentChanged(bool)),this,SLOT(slotPresentChanged(bool))); - } - m_pAccountNumber = PhoneDirectoryModel::instance().getNumber(currentUri,q_ptr); - m_pAccountNumber->setType(ContactMethod::Type::ACCOUNT); - connect(m_pAccountNumber,SIGNAL(presenceMessageChanged(QString)),this,SLOT(slotPresenceMessageChanged(QString))); - connect(m_pAccountNumber,SIGNAL(presentChanged(bool)),this,SLOT(slotPresentChanged(bool))); - } - - emit q_ptr->changed(q_ptr); - - //The registration state is cached, update that cache - updateState(); - - AccountModel::instance().d_ptr->slotVolatileAccountDetailsChange(q_ptr->id(),configurationManager.getVolatileAccountDetails(q_ptr->id())); - } -} - -void AccountPrivate::nothing() -{ - -} - -void AccountPrivate::edit() { - changeState(Account::EditState::EDITING ); -} - -void AccountPrivate::modify() { - typedef Account::RoleStatus ST; - typedef Account::Role R ; - //This check if the account can be saved or it would produce an invalid result - - //Future checks that could be implemented: - // * 2 accounts with the same alias - // * Weak password (will require a new COMPLETE_WARNING edit state) - // * Invalid hostname - // * Unreachable hostname (will require a new COMPLETE_WARNING edit state) - // * Invalid username - // * Non hash username for Ring accounts - - - /* ALIAS : While valid, an account without one cause usability issues */ - /* HOSTNAME: Without hostname, an account cannot be "READY" */ - /* USERNAME: All protocols but IP2IP require an username */ - /* PASSWORD: SIP accounts require a password (unless used as IP2IP) */ - - m_hRoleStatus[(int)R::Alias ] = q_ptr->alias ().isEmpty() ? ST::REQUIRED_EMPTY : ST::OK; - m_hRoleStatus[(int)R::Hostname] = q_ptr->hostname().isEmpty() ? ST::REQUIRED_EMPTY : ST::OK; - m_hRoleStatus[(int)R::Username] = q_ptr->username().isEmpty() ? ST::REQUIRED_EMPTY : ST::OK; - m_hRoleStatus[(int)R::Password] = q_ptr->password().isEmpty() ? ST::REQUIRED_EMPTY : ST::OK; - - //Apply some filters per protocol - switch (q_ptr->protocol()) { - case Account::Protocol::SIP: - //IP2IP is very permissive about missing fields - if (q_ptr->isIp2ip()) { - m_hRoleStatus[(int)R::Alias ] = ST::OK; - m_hRoleStatus[(int)R::Username] = ST::OK; - m_hRoleStatus[(int)R::Hostname] = ST::OK; - m_hRoleStatus[(int)R::Password] = ST::OK; - } - break; - case Account::Protocol::RING: - m_hRoleStatus[(int)R::Hostname] = ST::OK; - m_hRoleStatus[(int)R::Password] = ST::OK; - - //New accounts will get the hash later - if (q_ptr->isNew() && q_ptr->username().isEmpty()) - m_hRoleStatus[(int)R::Username] = ST::OK ; - else if (q_ptr->isNew() && !q_ptr->username().isEmpty()) - m_hRoleStatus[(int)R::Username] = ST::INVALID; - - break; - case Account::Protocol::COUNT__: - //No changes needed - break; - } - - const bool isIncomplete = ( - (m_hRoleStatus[(int) R::Alias ] != ST::OK) - | (m_hRoleStatus[(int) R::Hostname ] != ST::OK) - | (m_hRoleStatus[(int) R::Username ] != ST::OK) - | (m_hRoleStatus[(int) R::Password ] != ST::OK) - ); - - const Account::EditState newState = isIncomplete ? - Account::EditState::MODIFIED_INCOMPLETE : - Account::EditState::MODIFIED_COMPLETE ; - - if (newState != q_ptr->editState()) - changeState(newState); -} - -void AccountPrivate::remove() { - changeState(Account::EditState::REMOVED ); -} - -void AccountPrivate::cancel() { - changeState(Account::EditState::READY ); -} - -void AccountPrivate::outdate() { - changeState(Account::EditState::OUTDATED); -} - -void AccountPrivate::regenSecurityValidation() -{ - if (m_pSecurityEvaluationModel) { - m_pSecurityEvaluationModel->d_ptr->update(); - } -} - -/***************************************************************************** - * * - * Operator * - * * - ****************************************************************************/ - -///Are both account the same -bool Account::operator==(const Account& a)const -{ - return d_ptr->m_AccountId == a.d_ptr->m_AccountId; -} - -/***************************************************************************** - * * - * Placeholder * - * * - ****************************************************************************/ - -///Constructor -AccountPlaceHolder::AccountPlaceHolder(const QByteArray& uid) : Account(), -d_ptr(nullptr) -{ - Account::d_ptr->m_AccountId = uid ; - Account::d_ptr->m_isLoaded = false; -} - -/***************************************************************************** - * * - * Mutator * - * * - ****************************************************************************/ - -///Merge an existing account into this temporary one -bool AccountPrivate::merge(Account* account) -{ - if ((!account) || this == account->Account::d_ptr.data()) - return false; - - /*AccountPrivate* p = (AccountPrivate*) (q_ptr->Account::d_ptr.take()); - delete p;*/ //FIXME memory leak - - q_ptr->Account::d_ptr = account->Account::d_ptr; - emit q_ptr->changed(q_ptr); - - return true; -} - -/***************************************************************************** - * * - * Helper * - * * - ****************************************************************************/ - -void Account::regenSecurityValidation() -{ - d_ptr->regenSecurityValidation(); -} - -/** - * The client have a different point of view when it come to the account - * state. All the different errors are also handled elsewhere - */ -Account::RegistrationState Account::fromDaemonName(const QString& st) -{ - if ( st == DRing::Account::States::REGISTERED - || st == DRing::Account::States::READY ) - return Account::RegistrationState::READY; - - else if( st == DRing::Account::States::UNREGISTERED ) - return Account::RegistrationState::UNREGISTERED; - - else if( st == DRing::Account::States::TRYING ) - return Account::RegistrationState::TRYING; - - else if (st == DRing::Account::States::INITIALIZING ) - return Account::RegistrationState::INITIALIZING; - - else if( st == DRing::Account::States::ERROR - || st == DRing::Account::States::ERROR_GENERIC - || st == DRing::Account::States::ERROR_AUTH - || st == DRing::Account::States::ERROR_NETWORK - || st == DRing::Account::States::ERROR_HOST - || st == DRing::Account::States::ERROR_CONF_STUN - || st == DRing::Account::States::ERROR_EXIST_STUN - || st == DRing::Account::States::ERROR_SERVICE_UNAVAILABLE - || st == DRing::Account::States::ERROR_NOT_ACCEPTABLE - || st == DRing::Account::States::ERROR_NEED_MIGRATION - || st == DRing::Account::States::REQUEST_TIMEOUT ) - return Account::RegistrationState::ERROR; - - else { - qWarning() << "Unknown registration state" << st; - return Account::RegistrationState::ERROR; - } - -} - -#undef TO_BOOL -#undef IS_TRUE -#include <account.moc> diff --git a/src/account.h b/src/account.h deleted file mode 100644 index 901c2a9013fceddb91db6d3af0d289acc3025e8a..0000000000000000000000000000000000000000 --- a/src/account.h +++ /dev/null @@ -1,595 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * Nicolas Jäger <nicolas.jager@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QList> -#include <QtCore/QSharedPointer> - -//Qt -class QString; - -//Ring -#include "itembase.h" -#include "keyexchangemodel.h" -#include "uri.h" -#include "typedefs.h" -#include "itemdataroles.h" -#include "namedirectory.h" -#include "usage_statistics.h" - -class ContactMethod ; -class SecurityEvaluationModel ; -class Certificate ; -class KeyExchangeModelPrivate ; - -//Private -class AccountPrivate; -class AccountPlaceHolderPrivate; - - -///@enum DtmfType Different method to send the DTMF (key sound) to the peer -enum DtmfType { - OverRtp, - OverSip -}; -Q_ENUMS(DtmfType) - -/** - * A communication account. - * - * This class represent an account based around a protocol and a bunch of properties. - * - * Using the setters on this object won't cause the changes to take effect immediately. - * - * To save the changes, use the "<<" operator on the account with Account::EditAction::SAVE. - * Similarly, the Account::EditAction::RELOAD action will reset the changes to match the - * current properties used by daemon. - */ -class LIB_EXPORT Account : public ItemBase { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - - friend class AccountPlaceHolder; - friend class AccountModel; - - using ContactMethods = QVector<ContactMethod*>; - - //Properties - Q_PROPERTY(QByteArray id READ id ) - Q_PROPERTY(QString deviceId READ deviceId ) - Q_PROPERTY(QString alias READ alias WRITE setAlias ) - Q_PROPERTY(Account::Protocol protocol READ protocol WRITE setProtocol ) - Q_PROPERTY(QString hostname READ hostname WRITE setHostname ) - Q_PROPERTY(QString nameServiceURL READ nameServiceURL WRITE setNameServiceURL ) - Q_PROPERTY(QString registeredName READ registeredName ) - Q_PROPERTY(QString mailbox READ mailbox WRITE setMailbox ) - Q_PROPERTY(QString proxy READ proxy WRITE setProxy ) - Q_PROPERTY(QString tlsPassword READ tlsPassword WRITE setTlsPassword ) - Q_PROPERTY(Certificate* tlsCaListCertificate READ tlsCaListCertificate WRITE setTlsCaListCertificate ) - Q_PROPERTY(Certificate* tlsCertificate READ tlsCertificate WRITE setTlsCertificate ) - Q_PROPERTY(QString tlsPrivateKey READ tlsPrivateKey WRITE setTlsPrivateKey ) - Q_PROPERTY(QString tlsServerName READ tlsServerName WRITE setTlsServerName ) - Q_PROPERTY(QString sipStunServer READ sipStunServer WRITE setSipStunServer ) - Q_PROPERTY(QString publishedAddress READ publishedAddress WRITE setPublishedAddress ) - Q_PROPERTY(QString ringtonePath READ ringtonePath WRITE setRingtonePath ) - Q_PROPERTY(int registrationExpire READ registrationExpire WRITE setRegistrationExpire ) - Q_PROPERTY(int tlsNegotiationTimeoutSec READ tlsNegotiationTimeoutSec WRITE setTlsNegotiationTimeoutSec ) - Q_PROPERTY(int localPort READ localPort WRITE setLocalPort ) - Q_PROPERTY(int bootstrapPort READ bootstrapPort WRITE setBootstrapPort ) - Q_PROPERTY(int publishedPort READ publishedPort WRITE setPublishedPort ) - Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled ) - Q_PROPERTY(bool autoAnswer READ isAutoAnswer WRITE setAutoAnswer ) - Q_PROPERTY(bool tlsVerifyServer READ isTlsVerifyServer WRITE setTlsVerifyServer ) - Q_PROPERTY(bool tlsVerifyClient READ isTlsVerifyClient WRITE setTlsVerifyClient ) - Q_PROPERTY(bool tlsRequireClientCertificate READ isTlsRequireClientCertificate WRITE setTlsRequireClientCertificate ) - Q_PROPERTY(bool tlsEnabled READ isTlsEnabled WRITE setTlsEnabled ) - Q_PROPERTY(bool srtpRtpFallback READ isSrtpRtpFallback WRITE setSrtpRtpFallback ) - Q_PROPERTY(bool sipStunEnabled READ isSipStunEnabled WRITE setSipStunEnabled ) - Q_PROPERTY(bool publishedSameAsLocal READ isPublishedSameAsLocal WRITE setPublishedSameAsLocal ) - Q_PROPERTY(bool ringtoneEnabled READ isRingtoneEnabled WRITE setRingtoneEnabled ) - Q_PROPERTY(DtmfType dTMFType READ DTMFType WRITE setDTMFType ) - Q_PROPERTY(int voiceMailCount READ voiceMailCount WRITE setVoiceMailCount ) -// Q_PROPERTY(QString typeName READ type WRITE setType ) - Q_PROPERTY(QString presenceMessage READ presenceMessage ) - Q_PROPERTY(bool supportPresencePublish READ supportPresencePublish ) - Q_PROPERTY(bool supportPresenceSubscribe READ supportPresenceSubscribe ) - Q_PROPERTY(bool presenceEnabled READ presenceEnabled WRITE setPresenceEnabled NOTIFY presenceEnabledChanged) - Q_PROPERTY(bool videoEnabled READ isVideoEnabled WRITE setVideoEnabled ) - Q_PROPERTY(int videoPortMax READ videoPortMax WRITE setVideoPortMax ) - Q_PROPERTY(int videoPortMin READ videoPortMin WRITE setVideoPortMin ) - Q_PROPERTY(int audioPortMax READ audioPortMax WRITE setAudioPortMax ) - Q_PROPERTY(int audioPortMin READ audioPortMin WRITE setAudioPortMin ) - Q_PROPERTY(bool upnpEnabled READ isUpnpEnabled WRITE setUpnpEnabled ) - Q_PROPERTY(bool hasCustomUserAgent READ hasCustomUserAgent WRITE setHasCustomUserAgent ) - - Q_PROPERTY(QString userAgent READ userAgent WRITE setUserAgent ) - Q_PROPERTY(bool useDefaultPort READ useDefaultPort WRITE setUseDefaultPort ) - Q_PROPERTY(QString displayName READ displayName WRITE setDisplayName ) - Q_PROPERTY(QString archivePassword READ archivePassword WRITE setArchivePassword ) - Q_PROPERTY(QString archivePin READ archivePin WRITE setArchivePin ) - Q_PROPERTY(QString archivePath READ archivePath WRITE setArchivePath ) - Q_PROPERTY(RegistrationState registrationState READ registrationState WRITE setRegistrationState ) - Q_PROPERTY(bool usedForOutgogingCall READ isUsedForOutgogingCall ) - Q_PROPERTY(uint totalCallCount READ totalCallCount ) - Q_PROPERTY(uint weekCallCount READ weekCallCount ) - Q_PROPERTY(uint trimesterCallCount READ trimesterCallCount ) - Q_PROPERTY(time_t lastUsed READ lastUsed ) - - Q_PROPERTY(bool allowIncomingFromHistory READ allowIncomingFromHistory WRITE setAllowIncomingFromHistory ) - Q_PROPERTY(bool allowIncomingFromContact READ allowIncomingFromContact WRITE setAllowIncomingFromContact ) - Q_PROPERTY(bool allowIncomingFromUnknown READ allowIncomingFromUnknown WRITE setAllowIncomingFromUnknown ) - - Q_PROPERTY(KeyExchangeModel* keyExchangeModel READ keyExchangeModel ) - Q_PROPERTY(SecurityEvaluationModel* securityEvaluationModel READ securityEvaluationModel ) - Q_PROPERTY(QAbstractItemModel* knownCertificateModel READ knownCertificateModel ) - Q_PROPERTY(QAbstractItemModel* bannedCertificatesModel READ bannedCertificatesModel ) - Q_PROPERTY(QAbstractItemModel* allowedCertificatesModel READ allowedCertificatesModel ) - - Q_PROPERTY(QString proxyServer READ proxyServer WRITE setProxyServer ) - Q_PROPERTY(QString pushNotificationToken READ pushNotificationToken WRITE setPushNotificationToken ) - Q_PROPERTY(QString turnServer READ turnServer WRITE setTurnServer ) - Q_PROPERTY(QString turnServerUsername READ turnServerUsername WRITE setTurnServerUsername ) - Q_PROPERTY(QString turnServerPassword READ turnServerPassword WRITE setTurnServerPassword ) - Q_PROPERTY(QString turnServerRealm READ turnServerRealm WRITE setTurnServerRealm ) - - Q_PROPERTY(ContactMethods contactsFromDaemon READ getContacts ) - - public: - - ///@enum EditState: Manage how and when an account can be reloaded or change state - enum class EditState { - READY = 0, /*!< The account is synchronized */ - EDITING = 1, /*!< The account is "locked" by the client for edition */ - OUTDATED = 2, /*!< The remote and local details are out of sync */ - NEW = 3, /*!< The account is new, there is no remote */ - MODIFIED_INCOMPLETE = 4, /*!< The account has modified, but required fields are missing/invalid */ - MODIFIED_COMPLETE = 5, /*!< The account has modified and can be saved */ - REMOVED = 6, /*!< The account remote has been deleted */ - COUNT__ - }; - - ///@enum EditAction Actions that can be performed on the Account state - enum class EditAction { - NOTHING = 0, /*!< Do nothing */ - EDIT = 1, /*!< Lock the current details for edition */ - RELOAD = 2, /*!< Override the local details with the remote ones */ - SAVE = 3, /*!< Override the remote details with the local ones */ - REMOVE = 4, /*!< Remove this account */ - MODIFY = 5, /*!< Change the account details */ - CANCEL = 6, /*!< Cancel the modification, override with the remote */ - COUNT__ - }; - Q_ENUMS(EditAction) - - ///@enum RegistrationState The account state from a client point of view - enum class RegistrationState { - READY = 0, /*!< The account can be used to pass a call */ - UNREGISTERED = 1, /*!< The account isn't functional voluntarily */ - INITIALIZING = 2, /*!< The account being created */ - TRYING = 3, /*!< The account is trying to become ready */ - ERROR = 4, /*!< The account failed to become ready */ - COUNT__ - }; - Q_ENUMS(RegistrationState) - - enum class Role { - Alias = static_cast<int>(Ring::Role::UserRole) + 100, - Proto , - Hostname , - Username , - Mailbox , - Proxy , - TlsPassword , - TlsCaListCertificate , - TlsCertificate , - TlsPrivateKey , - TlsServerName , - SipStunServer , - PublishedAddress , - RingtonePath , - RegistrationExpire , - TlsNegotiationTimeoutSec , - TlsNegotiationTimeoutMsec , - LocalPort , - BootstrapPort , - PublishedPort , - Enabled , - AutoAnswer , - TlsVerifyServer , - TlsVerifyClient , - TlsRequireClientCertificate , - TlsEnabled , - SrtpRtpFallback , - SipStunEnabled , - PublishedSameAsLocal , - RingtoneEnabled , - dTMFType , - Id , - Object , - TypeName , - PresenceMessage , - RegistrationState , - UseDefaultPort , - UsedForOutgogingCall , - TotalCallCount , - WeekCallCount , - TrimesterCallCount , - LastUsed , - UserAgent , - Password , - SupportPresencePublish , - SupportPresenceSubscribe , - PresenceEnabled , - IsVideoEnabled , - VideoPortMax , - VideoPortMin , - AudioPortMin , - AudioPortMax , - IsUpnpEnabled , - HasCustomUserAgent , - LastTransportErrorCode , - LastTransportErrorMessage , - PushnotiticationToken , - ProxyServer , - ProxyEnabled , - TurnServer , - TurnServerEnabled , - TurnServerUsername , - TurnServerPassword , - TurnServerRealm , - HasProxy , - DisplayName , - SrtpEnabled , - KeyExchangeModel , - StatusModel , - SecurityEvaluationModel , - KnownCertificateModel , - BannedCertificatesModel , - AllowedCertificatesModel , - AllowIncomingFromHistory , - AllowIncomingFromContact , - AllowIncomingFromUnknown , - ActiveCallLimit , - HasActiveCallLimit , - SecurityLevel , - SecurityLevelIcon , - LastStatusChangeTimeStamp , - RegisteredName , - }; - - ///@enum RoleState Whether a role can be used in a certain context - enum class RoleState { - READ_WRITE , - READ_ONLY , - UNAVAILABLE, - }; - - ///@enum RoleStatus The current status of the role based on its value - enum class RoleStatus { - OK , /*!< The field is ok (the default) */ - UNTESTED , /*!< A test is in progress, no results yet (ex: network)*/ - INVALID , /*!< The content is invalid */ - REQUIRED_EMPTY, /*!< The field is empty but is required */ - OUT_OF_RANGE , /*!< The value is out of range */ - }; - - enum class Protocol { - SIP = 0, /*!< Used for both SIP and IP2IP calls */ - RING = 1, /*!< Used for RING-DHT calls */ - COUNT__, - }; - Q_ENUMS(Protocol) - - ///Possible account export status - enum class ExportOnRingStatus { - SUCCESS = 0, - WRONG_PASSWORD = 1 , - NETWORK_ERROR = 2 - }; - Q_ENUMS(ExportOnRingStatus) - - // Possible account migration status - enum class MigrationEndedStatus { - SUCCESS = 0, - UNDEFINED_STATUS = 1, - INVALID = 2, - }; - Q_ENUMS(MigrationEndedStatus) - - //Factory - static Account* buildExistingAccountFromId(const QByteArray& _accountId); - static Account* buildNewAccountFromAlias (Account::Protocol proto, const QString& alias); - - /** - *Perform an action - * @return If the state changed - */ - Q_INVOKABLE bool performAction(Account::EditAction action); - Account::EditState editState() const; - - //Getters - bool isNew () const; - const QByteArray id () const; - const QString toHumanStateName() const; - const QString alias () const; - QModelIndex index () const; - virtual bool isLoaded () const; - bool isIp2ip () const; - - KeyExchangeModel* keyExchangeModel () const; - SecurityEvaluationModel* securityEvaluationModel () const; - QAbstractItemModel* knownCertificateModel () const; - QAbstractItemModel* bannedCertificatesModel () const; - QAbstractItemModel* allowedCertificatesModel () const; - - Q_INVOKABLE RoleState roleState (Account::Role role) const; - Q_INVOKABLE RoleStatus roleStatus(Account::Role role) const; - - //Getters - QString hostname () const; - QString deviceId () const; - bool isEnabled () const; - bool isAutoAnswer () const; - QString username () const; - QString registeredName () const; - QString mailbox () const; - QString proxy () const; - QString nameServiceURL () const; - QString password () const; - bool isSrtpRtpFallback () const; - bool isSrtpEnabled () const; - bool isSipStunEnabled () const; - QString sipStunServer () const; - int registrationExpire () const; - bool isPublishedSameAsLocal () const; - QString publishedAddress () const; - int publishedPort () const; - QString tlsPassword () const; - int bootstrapPort () const; - Certificate* tlsCaListCertificate () const; - Certificate* tlsCertificate () const; - QString tlsPrivateKey () const; - QString tlsServerName () const; - int tlsNegotiationTimeoutSec () const; - bool isTlsVerifyServer () const; - bool isTlsVerifyClient () const; - bool isTlsRequireClientCertificate() const; - bool isTlsEnabled () const; - bool isRingtoneEnabled () const; - QString ringtonePath () const; - int localPort () const; - int voiceMailCount () const; - DtmfType DTMFType () const; - QString presenceMessage () const; - bool supportPresencePublish () const; - bool supportPresenceSubscribe () const; - bool presenceEnabled () const; - bool isVideoEnabled () const; - int videoPortMax () const; - int videoPortMin () const; - int audioPortMin () const; - int audioPortMax () const; - bool isUpnpEnabled () const; - bool hasCustomUserAgent () const; - QString lastTransportErrorMessage () const; - QString userAgent () const; - bool useDefaultPort () const; - bool isProxyEnabled () const; - QString pushNotificationToken () const; - QString proxyServer () const; - bool isTurnEnabled () const; - QString turnServer () const; - QString turnServerUsername () const; - QString turnServerPassword () const; - QString turnServerRealm () const; - bool hasProxy () const; - QString displayName () const; - bool archiveHasPassword () const; - QString archivePassword () const; - QString archivePin () const; - QString archivePath () const; - bool changePassword (const QString& currentPassword, const QString newPassword) const; - RegistrationState registrationState () const; - Protocol protocol () const; - ContactMethod* contactMethod () const; - bool allowIncomingFromUnknown () const; - bool allowIncomingFromHistory () const; - bool allowIncomingFromContact () const; - int activeCallLimit () const; - bool hasActiveCallLimit () const; - bool needsMigration () const; - uint internalId () const; - QString lastSipRegistrationStatus () const; - - Q_INVOKABLE bool exportOnRing (const QString& password) const; - Q_INVOKABLE bool exportToFile (const QString& destinationPath, const QString& password = {}) const; - Q_INVOKABLE bool registerName (const QString& password, const QString& name) const; - Q_INVOKABLE bool lookupName (const QString& name ) const; - Q_INVOKABLE bool lookupAddress(const QString& address ) const; - - bool isUsedForOutgogingCall () const; - uint totalCallCount () const; - uint weekCallCount () const; - uint trimesterCallCount () const; - time_t lastUsed () const; - - ContactMethods& getContacts () const; - - Q_INVOKABLE QVariant roleData ( int role ) const; - Q_INVOKABLE bool supportScheme ( URI::SchemeType type ) const; - Q_INVOKABLE bool allowCertificate( Certificate* c ) ; - Q_INVOKABLE bool banCertificate ( Certificate* c ) ; - Q_INVOKABLE bool removeContact(Certificate* c); - Q_INVOKABLE bool removeContact(const ContactMethod* c); - Q_INVOKABLE bool removeContact(const URI& uri); - Q_INVOKABLE bool addContact(Certificate* c); - Q_INVOKABLE bool addContact(const ContactMethod* c); - Q_INVOKABLE bool addContact(const URI& uri); - Q_INVOKABLE bool hasContact(ContactMethod* c); - Q_INVOKABLE QString accountDetail(const QString& param) const; - - //Setters - void setId (const QByteArray& id ); - void setAlias (const QString& detail ); - void setProtocol (Account::Protocol proto); - void setHostname (const QString& detail ); - void setUsername (const QString& detail ); - void setMailbox (const QString& detail ); - void setProxy (const QString& detail ); - void setNameServiceURL (const QString& detail ); - void setPassword (const QString& detail ); - void setTlsPassword (const QString& detail ); - void setTlsCaListCertificate (Certificate* cert ); - void setTlsCertificate (Certificate* cert ); - void setTlsCaListCertificate (const QString& detail ); - void setTlsCertificate (const QString& detail ); - void setTlsPrivateKey (const QString& path ); - void setTlsServerName (const QString& detail ); - void setSipStunServer (const QString& detail ); - void setPublishedAddress (const QString& detail ); - void setRingtonePath (const QString& detail ); - void setProxyEnabled (bool value ); - void setPushNotificationToken (const QString& token ); - void setProxyServer (const QString& value ); - void setTurnEnabled (bool value ); - void setTurnServer (const QString& value ); - void setTurnServerUsername (const QString& value ); - void setTurnServerPassword (const QString& value ); - void setTurnServerRealm (const QString& value ); - void setDisplayName (const QString& value ); - void setArchivePassword (const QString& value ); - void setArchivePin (const QString& value ); - void setArchivePath (const QString& value ); - void setVoiceMailCount (int count ); - void setRegistrationExpire (int detail); - void setTlsNegotiationTimeoutSec (int detail); - void setLocalPort (unsigned short detail); - void setBootstrapPort (unsigned short detail); - void setPublishedPort (unsigned short detail); - void setAutoAnswer (bool detail); - void setTlsVerifyServer (bool detail); - void setTlsVerifyClient (bool detail); - void setTlsRequireClientCertificate (bool detail); - void setTlsEnabled (bool detail); - void setSrtpRtpFallback (bool detail); - void setSrtpEnabled (bool detail); - void setSipStunEnabled (bool detail); - void setPublishedSameAsLocal (bool detail); - void setRingtoneEnabled (bool detail); - void setPresenceEnabled (bool enable); - void setVideoEnabled (bool enable); - void setAudioPortMax (int port ); - void setAudioPortMin (int port ); - void setVideoPortMax (int port ); - void setVideoPortMin (int port ); - void setActiveCallLimit (int value ); - void setDTMFType (DtmfType type); - void setUserAgent (const QString& agent); - void setUpnpEnabled (bool enable); - void setHasCustomUserAgent (bool enable); - void setUseDefaultPort (bool value ); - void setAllowIncomingFromHistory (bool value ); - void setAllowIncomingFromContact (bool value ); - void setAllowIncomingFromUnknown (bool value ); - void setHasActiveCallLimit (bool value ); - void setLastSipRegistrationStatus (const QString& value ); - void setLastTransportCode (int value ); - void setLastTransportMessage (const QString& value ); - void setRegistrationState (const RegistrationState& value ); - void setRoleData(int role, const QVariant& value); - - bool setAccountProperty(const QString& param, const QString& val); - - //Mutator - bool updateState(); - - //Operators - bool operator==(const Account&)const; - Account* operator<<(Account::EditAction& action); - - //Helper - static Account::RegistrationState fromDaemonName(const QString& st); - void regenSecurityValidation(); - - //Variable - UsageStatistics usageStats; - - public Q_SLOTS: - void setEnabled(bool checked); - - private: - //Constructors - explicit Account(); - ~Account(); - - QSharedPointer<AccountPrivate> d_ptr; - Q_DECLARE_PRIVATE(Account) - Q_DISABLE_COPY(Account) - - Q_SIGNALS: - ///The account state (Invalid,Trying,Registered) changed - void stateChanged(Account::RegistrationState state); - ///One of the account property changed - //TODO Qt5 drop the account parameter - void propertyChanged(Account* a, const QString& name, const QString& newVal, const QString& oldVal); - ///Something(s) in the account changed - void changed(Account* a); - ///The alias changed, take effect instantaneously - void aliasChanged(const QString&); - ///The presence support changed - void presenceEnabledChanged(bool); - ///The account has been enabled/disabled - void enabled(bool); - ///The account edit state changed - void editStateChanged(const EditState state, const EditState previous); - ///Export on Ring has ended - void exportOnRingEnded(Account::ExportOnRingStatus status, const QString& pin); - ///RegisterName has ended - void nameRegistrationEnded(NameDirectory::RegisterNameStatus status, const QString& name); - ///Name or address lookup has completed - void registeredNameFound(NameDirectory::LookupStatus status, const QString& address, const QString& name); - /// Migration ended - void migrationEnded(const Account::MigrationEndedStatus); -}; -Q_DECLARE_METATYPE(Account*) -Q_DECLARE_METATYPE(const Account*) -Q_DECLARE_METATYPE(Account::RegistrationState) -Q_DECLARE_METATYPE(Account::EditAction) -Q_DECLARE_METATYPE(Account::Protocol) -Q_DECLARE_METATYPE(DtmfType) - -Account* operator<<(Account* a, Account::EditAction action); - -/** - * Some accounts can be loaded at later time. This object will be upgraded - * to an account when it arrive - */ -class LIB_EXPORT AccountPlaceHolder : public Account { - Q_OBJECT - friend class AccountModel; - -private: - explicit AccountPlaceHolder(const QByteArray& uid); - - AccountPlaceHolderPrivate* d_ptr; - Q_DECLARE_PRIVATE(AccountPlaceHolder) -}; diff --git a/src/accountmodel.cpp b/src/accountmodel.cpp deleted file mode 100644 index e559b2e252e1da37e752673ca2aa0b44733cddbd..0000000000000000000000000000000000000000 --- a/src/accountmodel.cpp +++ /dev/null @@ -1,1197 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * Nicolas Jäger <nicolas.jager@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -//Parent -#include "accountmodel.h" - -//Std -#include <atomic> -#include <algorithm> - -//Qt -#include <QtCore/QObject> -#include <QtCore/QCoreApplication> -#include <QtCore/QItemSelectionModel> -#include <QtCore/QMimeData> -#include <QtCore/QDir> - -//Ring daemon -#include <account_const.h> - -//Ring library -#include "account.h" -#include "mime.h" -#include "private/accountmodel_p.h" -#include "dbus/configurationmanager.h" -#include "dbus/callmanager.h" -#include "dbus/instancemanager.h" -#include "dbus/presencemanager.h" -#include "person.h" -#include "private/vcardutils.h" -#include "phonedirectorymodel.h" -#include "contactmethod.h" - -QHash<QByteArray,AccountPlaceHolder*> AccountModelPrivate::m_hsPlaceHolder; - -AccountModelPrivate::AccountModelPrivate(AccountModel* parent) : QObject(parent),q_ptr(parent), -m_pIP2IP(nullptr),m_pSelectionModel(nullptr),m_lMimes({RingMimes::ACCOUNT}), -m_lSupportedProtocols {{ - /* SIP */ false, - /* RING */ false, -}} -{} - -///Constructors -AccountModel::AccountModel() - : QAbstractListModel(QCoreApplication::instance()) - , d_ptr(new AccountModelPrivate(this)) -{} - -void AccountModelPrivate::init() -{ - InstanceManager::instance(); // Make sure the daemon is running before calling updateAccounts() - q_ptr->updateAccounts(); - - CallManagerInterface& callManager = CallManager::instance(); - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - connect(&configurationManager, &ConfigurationManagerInterface::registrationStateChanged,this , - &AccountModelPrivate::slotDaemonAccountChanged, Qt::QueuedConnection); - connect(&configurationManager, SIGNAL(accountsChanged()) ,q_ptr, - SLOT(updateAccounts()), Qt::QueuedConnection); - connect(&callManager , SIGNAL(voiceMailNotify(QString,int)) ,this , - SLOT(slotVoiceMailNotify(QString,int)) ); - connect(&configurationManager, SIGNAL(volatileAccountDetailsChanged(QString,MapStringString)),this, - SLOT(slotVolatileAccountDetailsChange(QString,MapStringString)), Qt::QueuedConnection); - connect(&configurationManager, &ConfigurationManagerInterface::exportOnRingEnded, this, - &AccountModelPrivate::slotExportOnRingEnded, Qt::QueuedConnection); - connect(&configurationManager, &ConfigurationManagerInterface::migrationEnded, this, - &AccountModelPrivate::slotMigrationEnded, Qt::QueuedConnection); - connect(&configurationManager, &ConfigurationManagerInterface::contactAdded, this, - &AccountModelPrivate::slotContactAdded, Qt::QueuedConnection); - connect(&configurationManager, &ConfigurationManagerInterface::contactRemoved, this, - &AccountModelPrivate::slotContactRemoved, Qt::QueuedConnection); -} - -///Destructor -AccountModel::~AccountModel() -{ - while(d_ptr->m_lAccounts.size()) { - Account* a = d_ptr->m_lAccounts[0]; - d_ptr->m_lAccounts.remove(0); - delete a; - } - for(Account* a : d_ptr->m_pRemovedAccounts) { - delete a; - } - delete d_ptr; -} - -#define CAST(item) static_cast<int>(item) -QHash<int,QByteArray> AccountModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles.insert(CAST(Account::Role::Alias ) ,QByteArray("alias" )); - roles.insert(CAST(Account::Role::Proto ) ,QByteArray("protocol" )); - roles.insert(CAST(Account::Role::Hostname ) ,QByteArray("hostname" )); - roles.insert(CAST(Account::Role::Username ) ,QByteArray("username" )); - roles.insert(CAST(Account::Role::Mailbox ) ,QByteArray("mailbox" )); - roles.insert(CAST(Account::Role::Proxy ) ,QByteArray("proxy" )); - roles.insert(CAST(Account::Role::TlsPassword ) ,QByteArray("tlsPassword" )); - roles.insert(CAST(Account::Role::TlsCaListCertificate ) ,QByteArray("tlsCaListCertificate" )); - roles.insert(CAST(Account::Role::TlsCertificate ) ,QByteArray("tlsCertificate" )); - roles.insert(CAST(Account::Role::TlsServerName ) ,QByteArray("tlsServerName" )); - roles.insert(CAST(Account::Role::SipStunServer ) ,QByteArray("sipStunServer" )); - roles.insert(CAST(Account::Role::PublishedAddress ) ,QByteArray("publishedAddress" )); - roles.insert(CAST(Account::Role::RingtonePath ) ,QByteArray("ringtonePath" )); - roles.insert(CAST(Account::Role::RegistrationExpire ) ,QByteArray("registrationExpire" )); - roles.insert(CAST(Account::Role::TlsNegotiationTimeoutSec ) ,QByteArray("tlsNegotiationTimeoutSec" )); - roles.insert(CAST(Account::Role::TlsNegotiationTimeoutMsec ) ,QByteArray("tlsNegotiationTimeoutMsec" )); - roles.insert(CAST(Account::Role::LocalPort ) ,QByteArray("localPort" )); - roles.insert(CAST(Account::Role::BootstrapPort ) ,QByteArray("bootstrapPort" )); - roles.insert(CAST(Account::Role::PublishedPort ) ,QByteArray("publishedPort" )); - roles.insert(CAST(Account::Role::Enabled ) ,QByteArray("enabled" )); - roles.insert(CAST(Account::Role::AutoAnswer ) ,QByteArray("autoAnswer" )); - roles.insert(CAST(Account::Role::TlsVerifyServer ) ,QByteArray("tlsVerifyServer" )); - roles.insert(CAST(Account::Role::TlsVerifyClient ) ,QByteArray("tlsVerifyClient" )); - roles.insert(CAST(Account::Role::TlsRequireClientCertificate ) ,QByteArray("tlsRequireClientCertificate" )); - roles.insert(CAST(Account::Role::TlsEnabled ) ,QByteArray("tlsEnabled" )); - roles.insert(CAST(Account::Role::SrtpRtpFallback ) ,QByteArray("srtpRtpFallback" )); - roles.insert(CAST(Account::Role::SipStunEnabled ) ,QByteArray("sipStunEnabled" )); - roles.insert(CAST(Account::Role::PublishedSameAsLocal ) ,QByteArray("publishedSameAsLocal" )); - roles.insert(CAST(Account::Role::RingtoneEnabled ) ,QByteArray("ringtoneEnabled" )); - roles.insert(CAST(Account::Role::dTMFType ) ,QByteArray("dTMFType" )); - roles.insert(CAST(Account::Role::Id ) ,QByteArray("id" )); - roles.insert(CAST(Account::Role::Object ) ,QByteArray("object" )); - roles.insert(CAST(Account::Role::TypeName ) ,QByteArray("typeName" )); - roles.insert(CAST(Account::Role::PresenceMessage ) ,QByteArray("presenceMessage" )); - roles.insert(CAST(Account::Role::UsedForOutgogingCall ) ,QByteArray("usedForOutgogingCall" )); - roles.insert(CAST(Account::Role::TotalCallCount ) ,QByteArray("totalCallCount" )); - roles.insert(CAST(Account::Role::WeekCallCount ) ,QByteArray("weekCallCount" )); - roles.insert(CAST(Account::Role::TrimesterCallCount ) ,QByteArray("trimesterCallCount" )); - roles.insert(CAST(Account::Role::LastUsed ) ,QByteArray("lastUsed" )); - roles.insert(CAST(Account::Role::UserAgent ) ,QByteArray("userAgent" )); - roles.insert(CAST(Account::Role::Password ) ,QByteArray("password" )); - roles.insert(CAST(Account::Role::SupportPresencePublish ) ,QByteArray("supportPresencePublish" )); - roles.insert(CAST(Account::Role::SupportPresenceSubscribe ) ,QByteArray("supportPresenceSubscribe" )); - roles.insert(CAST(Account::Role::PresenceEnabled ) ,QByteArray("presenceEnabled" )); - roles.insert(CAST(Account::Role::IsVideoEnabled ) ,QByteArray("isVideoEnabled" )); - roles.insert(CAST(Account::Role::VideoPortMax ) ,QByteArray("videoPortMax" )); - roles.insert(CAST(Account::Role::VideoPortMin ) ,QByteArray("videoPortMin" )); - roles.insert(CAST(Account::Role::AudioPortMin ) ,QByteArray("audioPortMin" )); - roles.insert(CAST(Account::Role::AudioPortMax ) ,QByteArray("audioPortMax" )); - roles.insert(CAST(Account::Role::IsUpnpEnabled ) ,QByteArray("upnpEnabled" )); - roles.insert(CAST(Account::Role::HasCustomUserAgent ) ,QByteArray("hasCustomUserAgent" )); - roles.insert(CAST(Account::Role::LastTransportErrorCode ) ,QByteArray("lastTransportErrorCode" )); - roles.insert(CAST(Account::Role::LastTransportErrorMessage ) ,QByteArray("lastTransportErrorMessage" )); - roles.insert(CAST(Account::Role::UserAgent ) ,QByteArray("userAgent" )); - roles.insert(CAST(Account::Role::UseDefaultPort ) ,QByteArray("useDefaultPort" )); - roles.insert(CAST(Account::Role::TurnServer ) ,QByteArray("turnServer" )); - roles.insert(CAST(Account::Role::HasProxy ) ,QByteArray("hasProxy" )); - roles.insert(CAST(Account::Role::DisplayName ) ,QByteArray("displayName" )); - roles.insert(CAST(Account::Role::SrtpEnabled ) ,QByteArray("srtpEnabled" )); - roles.insert(CAST(Account::Role::KeyExchangeModel ) ,QByteArray("keyExchangeModel" )); - roles.insert(CAST(Account::Role::SecurityEvaluationModel ) ,QByteArray("securityEvaluationModel" )); - roles.insert(CAST(Account::Role::KnownCertificateModel ) ,QByteArray("knownCertificateModel" )); - roles.insert(CAST(Account::Role::BannedCertificatesModel ) ,QByteArray("bannedCertificatesModel" )); - roles.insert(CAST(Account::Role::AllowedCertificatesModel ) ,QByteArray("allowedCertificatesModel" )); - roles.insert(CAST(Account::Role::AllowIncomingFromHistory ) ,QByteArray("allowIncomingFromHistory" )); - roles.insert(CAST(Account::Role::AllowIncomingFromContact ) ,QByteArray("allowIncomingFromContact" )); - roles.insert(CAST(Account::Role::AllowIncomingFromUnknown ) ,QByteArray("allowIncomingFromUnknown" )); - roles.insert(CAST(Account::Role::ActiveCallLimit ) ,QByteArray("activeCallLimit" )); - roles.insert(CAST(Account::Role::HasActiveCallLimit ) ,QByteArray("hasActiveCallLimit" )); - roles.insert(CAST(Account::Role::SecurityLevel ) ,QByteArray("securityLevel" )); - roles.insert(CAST(Account::Role::SecurityLevelIcon ) ,QByteArray("securityLevelIcon" )); - roles.insert(CAST(Account::Role::TurnServerUsername ) ,QByteArray("turnServerUsername" )); - roles.insert(CAST(Account::Role::TurnServerPassword ) ,QByteArray("turnServerPassword" )); - roles.insert(CAST(Account::Role::TurnServerRealm ) ,QByteArray("turnServerRealm" )); - roles.insert(CAST(Account::Role::TurnServerEnabled ) ,QByteArray("turnEnabled" )); - roles.insert(CAST(Account::Role::TlsPrivateKey ) ,QByteArray("tlsPrivateKey" )); - roles.insert(CAST(Account::Role::LastStatusChangeTimeStamp ) ,QByteArray("lastStatusChangeTimeStamp" )); - roles.insert(CAST(Account::Role::RegisteredName ) ,QByteArray("registeredName" )); - - } - return roles; -} -#undef CAST - -///Get the first IP2IP account -Account* AccountModel::ip2ip() const -{ - if (!d_ptr->m_pIP2IP) { - foreach(Account* a, d_ptr->m_lAccounts) { - if (a->isIp2ip()) - d_ptr->m_pIP2IP = a; - } - } - return d_ptr->m_pIP2IP; -} - -///Singleton -AccountModel& AccountModel::instance() -{ - static auto instance = new AccountModel; - - // Upload account configuration only once in re-entrant way - static std::atomic_flag init_flag {ATOMIC_FLAG_INIT}; - if (not init_flag.test_and_set()) - instance->d_ptr->init(); - - return *instance; -} - -QItemSelectionModel* AccountModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<AccountModel*>(this)); - - return d_ptr->m_pSelectionModel; -} - - -QItemSelectionModel* AccountModel::userSelectionModel() const -{ - if (!d_ptr->m_pUserSelectionModel) - d_ptr->m_pUserSelectionModel = new QItemSelectionModel(const_cast<AccountModel*>(this)); - - return d_ptr->m_pUserSelectionModel; -} - -/** - * returns the select account - */ -Account* -AccountModel::selectedAccount() const -{ - auto accIdx = AccountModel::instance().selectionModel()->currentIndex(); - return AccountModel::instance().getAccountByModelIndex(accIdx); -} - -/** - * Helper method to update the selected index in user selection model - */ -void -AccountModel::setUserChosenAccount(Account* account) -{ - if (!account) { - return; - } - - const auto idx = account->index(); - - userSelectionModel()->setCurrentIndex( - idx, QItemSelectionModel::ClearAndSelect - ); -} - -/** - * returns the user chosen account - */ -Account* -AccountModel::userChosenAccount() const -{ - auto accIdx = AccountModel::instance().userSelectionModel()->currentIndex(); - return AccountModel::instance().getAccountByModelIndex(accIdx); -} - -QList<Account*> AccountModel::accountsToMigrate() const -{ - QList<Account*> accounts; - foreach(Account* account, d_ptr->m_lAccounts) { - if (account->needsMigration()) - accounts << account; - } - return accounts; -} - -/** - * returns a vector of contacts from the daemon - * @param account the account to query - * @return contacts a QVector<QMap<QString, QString>> - */ -QVector<QMap<QString, QString>> -AccountModel::getContacts(const Account* account) const -{ - return ConfigurationManager::instance().getContacts(account->id().data()); -} - -///Account status changed -void AccountModelPrivate::slotDaemonAccountChanged(const QString& account, const QString& registration_state, unsigned code, const QString& status) -{ - Q_UNUSED(registration_state); - Account* a = q_ptr->getById(account.toLatin1()); - - if (!a || (a && a->lastSipRegistrationStatus() != status )) { - if (status != "OK") //Do not pollute the log - qDebug() << "Account" << account << "status changed to" << status; - } - - if (a) - a->setLastSipRegistrationStatus(status); - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - //The account may have been deleted by the user, but 'apply' have not been pressed - if (!a) { - qDebug() << "received account changed for non existing account" << account; - const QStringList accountIds = configurationManager.getAccountList(); - for (int i = 0; i < accountIds.size(); ++i) { - if ((!q_ptr->getById(accountIds[i].toLatin1())) && m_lDeletedAccounts.indexOf(accountIds[i]) == -1) { - Account* acc = Account::buildExistingAccountFromId(accountIds[i].toLatin1()); - qDebug() << "building missing account" << accountIds[i]; - insertAccount(acc,i); - connect(acc, &Account::changed , this, &AccountModelPrivate::slotAccountChanged ); - connect(acc, &Account::presenceEnabledChanged , this, &AccountModelPrivate::slotAccountPresenceEnabledChanged ); - connect(acc, &Account::enabled , this, &AccountModelPrivate::slotSupportedProtocolsChanged ); - emit q_ptr->dataChanged(q_ptr->index(i,0),q_ptr->index(q_ptr->size()-1)); - emit q_ptr->layoutChanged(); - - if (!acc->isIp2ip()) - enableProtocol(acc->protocol()); - - } - } - - // remove any accounts that are not found in the daemon and which are marked to be REMOVED - // its not clear to me why this would ever happen in the first place, but the code does seem - // to be able to enter into this state... - QMutableVectorIterator<Account *> accIter(m_lAccounts); - int modelRow = 0; - while (accIter.hasNext()) { - auto acc = accIter.next(); - const int daemonRow = accountIds.indexOf(acc->id()); - - if (daemonRow == -1 && (acc->editState() == Account::EditState::READY || acc->editState() == Account::EditState::REMOVED)) { - q_ptr->beginRemoveRows(QModelIndex(), modelRow, modelRow); - accIter.remove(); - q_ptr->endRemoveRows(); - - // should we put it in the list of deleted accounts? who knows? - - // decrement which row we're on - --modelRow; - } - // we're going to the next row - ++modelRow; - } - } - else { - const bool isRegistered = a->registrationState() == Account::RegistrationState::READY; - a->updateState(); - const QModelIndex idx = a->index(); - emit q_ptr->dataChanged(idx, idx); - const bool regStateChanged = isRegistered != (a->registrationState() == Account::RegistrationState::READY); - - //Handle some important events directly - if (regStateChanged && (code == 502 || code == 503)) { - emit q_ptr->badGateway(); - } - else if (regStateChanged) - emit q_ptr->registrationChanged(a,a->registrationState() == Account::RegistrationState::READY); - - //Make sure volatile details get reloaded - //TODO eventually remove this call and trust the signal - slotVolatileAccountDetailsChange(account,configurationManager.getVolatileAccountDetails(account)); - - emit q_ptr->accountStateChanged(a,a->registrationState()); - } - -} - -void AccountModelPrivate::slotSupportedProtocolsChanged() -{ - emit q_ptr->supportedProtocolsChanged(); -} - -///Tell the model something changed -void AccountModelPrivate::slotAccountChanged(Account* a) -{ - int idx = m_lAccounts.indexOf(a); - if (idx != -1) { - emit q_ptr->dataChanged(q_ptr->index(idx, 0), q_ptr->index(idx, 0)); - } -} - - -/***************************************************************************** - * * - * Mutator * - * * - ****************************************************************************/ - - -///When a new voice mail is available -void AccountModelPrivate::slotVoiceMailNotify(const QString &accountID, int count) -{ - Account* a = q_ptr->getById(accountID.toLatin1()); - if (a) { - a->setVoiceMailCount(count); - emit q_ptr->voiceMailNotify(a,count); - } -} - -///Propagate account presence state -void AccountModelPrivate::slotAccountPresenceEnabledChanged(bool state) -{ - Q_UNUSED(state) - emit q_ptr->presenceEnabledChanged(q_ptr->isPresenceEnabled()); -} - -///Emitted when some runtime details changes -void AccountModelPrivate::slotVolatileAccountDetailsChange(const QString& accountId, const MapStringString& details) -{ - Account* a = q_ptr->getById(accountId.toLatin1()); - if (a) { - const int transportCode = details[DRing::Account::VolatileProperties::Transport::STATE_CODE].toInt(); - const QString transportDesc = details[DRing::Account::VolatileProperties::Transport::STATE_DESC]; - const QString status = details[DRing::Account::VolatileProperties::Registration::STATUS]; - - a->setLastTransportCode(transportCode); - a->setLastTransportMessage(transportDesc); - - const Account::RegistrationState state = Account::fromDaemonName(a->accountDetail(DRing::Account::ConfProperties::Registration::STATUS)); - a->setRegistrationState(state); - } -} - -///Export on Ring ended -void AccountModelPrivate::slotExportOnRingEnded(const QString& accountId, int status, const QString& pin) -{ - qDebug() << "Export on ring ended" << accountId; - - Account* a = q_ptr->getById(accountId.toLatin1()); - - if (!a) { - qWarning() << "export on Ring ended for unknown account" << accountId; - return; - } - - emit a->exportOnRingEnded(static_cast<Account::ExportOnRingStatus>(status), pin); -} - -/// Migration ended -void -AccountModelPrivate::slotMigrationEnded(const QString& accountId, const QString& result) -{ - Account* a = q_ptr->getById(accountId.toLatin1()); - - Account::MigrationEndedStatus status; - if(result == "SUCCESS") - status = Account::MigrationEndedStatus::SUCCESS; - else if(result == "INVALID") - status = Account::MigrationEndedStatus::INVALID; - else - status = Account::MigrationEndedStatus::UNDEFINED_STATUS; - - - if (status == Account::MigrationEndedStatus::UNDEFINED_STATUS) - qWarning() << "cannot emit migrationEnded signal, status is undefined"; - else - emit a->migrationEnded(status); -} - - -/// slot function used with ConfigurationManagerInterface::contactAdded signal -void -AccountModelPrivate::slotContactAdded(const QString &accountID, const QString &uri, bool confirmed) -{ - if (auto account = q_ptr->getById(accountID.toLatin1())) { - if (auto cm = PhoneDirectoryModel::instance().getNumber(uri, account)) { - cm->setConfirmed(confirmed); - auto& daemon_contacts = account->getContacts(); - if (not daemon_contacts.contains(cm)) - daemon_contacts << cm; - } - } -} - -/** - * slot function used with ConfigurationManagerInterface::contactRemoved signal - */ -void -AccountModelPrivate::slotContactRemoved(const QString &accountID, const QString &uri, bool banned) -{ - if (auto account = q_ptr->getById(accountID.toLatin1())) { - if (auto cm = PhoneDirectoryModel::instance().getNumber(uri, account)) { - auto& daemon_contacts = account->getContacts(); - // TODO: removeAll() is 5.4 - not yet supported by debian 8 - auto index = daemon_contacts.indexOf(cm); - if (index >= 0) - daemon_contacts.remove(index); - } - } -} - -///Update accounts -void AccountModel::update() -{ - ConfigurationManagerInterface & configurationManager = ConfigurationManager::instance(); - QList<Account*> tmp; - for (int i = 0; i < d_ptr->m_lAccounts.size(); i++) - tmp << d_ptr->m_lAccounts[i]; - - for (int i = 0; i < tmp.size(); i++) { - Account* current = tmp[i]; - if (!current->isNew() && (current->editState() != Account::EditState::NEW - && current->editState() != Account::EditState::MODIFIED_COMPLETE - && current->editState() != Account::EditState::MODIFIED_INCOMPLETE - && current->editState() != Account::EditState::OUTDATED)) - remove(current); - } - //ask for the list of accounts ids to the configurationManager - const QStringList accountIds = configurationManager.getAccountList(); - for (int i = 0; i < accountIds.size(); ++i) { - if (d_ptr->m_lDeletedAccounts.indexOf(accountIds[i]) == -1) { - Account* a = Account::buildExistingAccountFromId(accountIds[i].toLatin1()); - d_ptr->insertAccount(a,i); - emit dataChanged(index(i,0),index(size()-1,0)); - connect(a,SIGNAL(changed(Account*)),d_ptr,SLOT(slotAccountChanged(Account*))); - //connect(a,SIGNAL(propertyChanged(Account*,QString,QString,QString)),d_ptr,SLOT(slotAccountChanged(Account*))); - connect(a,SIGNAL(presenceEnabledChanged(bool)),d_ptr,SLOT(slotAccountPresenceEnabledChanged(bool))); - emit layoutChanged(); - - if (!a->isIp2ip()) - d_ptr->enableProtocol(a->protocol()); - } - } -} //update - -///Update accounts -void AccountModel::updateAccounts() -{ - qDebug() << "Updating all accounts"; - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - QStringList accountIds = configurationManager.getAccountList(); - - // Detect removed accounts - foreach(Account* account, d_ptr->m_lAccounts) { - if (accountIds.indexOf(account->id()) == -1) { - remove(account); - } - } - - //m_lAccounts.clear(); - for (int i = 0; i < accountIds.size(); ++i) { - Account* acc = getById(accountIds[i].toLatin1()); - if (!acc) { - Account* a = Account::buildExistingAccountFromId(accountIds[i].toLatin1()); - d_ptr->insertAccount(a,d_ptr->m_lAccounts.size()); - connect(a,SIGNAL(changed(Account*)),d_ptr,SLOT(slotAccountChanged(Account*))); - //connect(a,SIGNAL(propertyChanged(Account*,QString,QString,QString)),d_ptr,SLOT(slotAccountChanged(Account*))); - connect(a,SIGNAL(presenceEnabledChanged(bool)),d_ptr,SLOT(slotAccountPresenceEnabledChanged(bool))); - emit dataChanged(index(size()-1,0),index(size()-1,0)); - - if (!a->isIp2ip()) - d_ptr->enableProtocol(a->protocol()); - - emit accountAdded(a); - } - else { - acc->performAction(Account::EditAction::RELOAD); - } - } - emit accountListUpdated(); -} //updateAccounts - -///Save accounts details and reload it -void AccountModel::save() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList accountIds = QStringList(configurationManager.getAccountList()); - - //create or update each account from accountList - for (int i = 0; i < size(); i++) { - Account* current = (*this)[i]; - current->performAction(Account::EditAction::SAVE); - } - - //remove accounts that are in the configurationManager but not in the client - for (int i = 0; i < accountIds.size(); i++) { - if(!getById(accountIds[i].toLatin1())) { - configurationManager.removeAccount(accountIds[i]); - } - } - - //Set account order - QString order; - for( int i = 0 ; i < size() ; i++) - order += d_ptr->m_lAccounts[i]->id() + '/'; - configurationManager.setAccountsOrder(order); - d_ptr->m_lDeletedAccounts.clear(); -} - -int AccountModel::exportAccounts(const QStringList& accountIDs, const QString& filePath, const QString& password) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return configurationManager.exportAccounts(accountIDs, filePath, password); -} - -int AccountModel::importAccounts(const QString& filePath, const QString& password) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return configurationManager.importAccounts(filePath, password); -} - -///Move account up -bool AccountModel::moveUp() -{ - if (d_ptr->m_pSelectionModel) { - const QModelIndex& idx = d_ptr->m_pSelectionModel->currentIndex(); - - if (!idx.isValid()) - return false; - - if (dropMimeData(mimeData({idx}), Qt::MoveAction, idx.row()-1, idx.column(),idx.parent())) { - return true; - } - } - return false; -} - -///Move account down -bool AccountModel::moveDown() -{ - if (d_ptr->m_pSelectionModel) { - const QModelIndex& idx = d_ptr->m_pSelectionModel->currentIndex(); - - if (!idx.isValid()) - return false; - - if (dropMimeData(mimeData({idx}), Qt::MoveAction, idx.row()+1, idx.column(),idx.parent())) { - return true; - } - } - return false; -} - -///Try to register all enabled accounts -void AccountModel::registerAllAccounts() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.registerAllAccounts(); -} - -///Cancel all modifications -void AccountModel::cancel() { - foreach (Account* a, d_ptr->m_lAccounts) { - // Account::EditState::NEW is only for new and unmodified accounts - if (a->isNew()) - remove(a); - else { - switch(a->editState()) { - case Account::EditState::NEW : - remove(a); - break; - case Account::EditState::MODIFIED_INCOMPLETE: - case Account::EditState::MODIFIED_COMPLETE : - a << Account::EditAction::CANCEL; - break; - case Account::EditState::OUTDATED : - a << Account::EditAction::RELOAD; - break; - case Account::EditState::READY : - case Account::EditState::REMOVED : - case Account::EditState::EDITING : - case Account::EditState::COUNT__ : - break; - } - } - } - d_ptr->m_lDeletedAccounts.clear(); -} - - -void AccountModelPrivate::enableProtocol(Account::Protocol proto) -{ - const bool cache = m_lSupportedProtocols[proto]; - - //Set the supported protocol bits, for now, this intentionally ignore account states - m_lSupportedProtocols.setAt(proto, true); - - if (!cache) { - emit q_ptr->supportedProtocolsChanged(); - } -} - -AccountModel::EditState AccountModelPrivate::convertAccountEditState(const Account::EditState s) -{ - AccountModel::EditState ams = AccountModel::EditState::INVALID; - - switch (s) { - case Account::EditState::READY : - case Account::EditState::OUTDATED : - case Account::EditState::EDITING : - case Account::EditState::COUNT__ : - ams = AccountModel::EditState::SAVED; - break; - case Account::EditState::MODIFIED_INCOMPLETE: - ams = AccountModel::EditState::INVALID; - break; - case Account::EditState::NEW : - case Account::EditState::REMOVED : - case Account::EditState::MODIFIED_COMPLETE : - ams = AccountModel::EditState::UNSAVED; - break; - } - - return ams; -} - -///Check if the AccountModel need/can be saved as a whole -AccountModel::EditState AccountModel::editState() const -{ - typedef AccountModel::EditState ES ; - typedef const Account::EditState AES; - - static ES s_CurrentState = ES::INVALID; - - //This class is a singleton, so using static variables is ok - static Matrix1D<ES,int> estates = { - { ES::SAVED , 0}, - { ES::UNSAVED , 0}, - { ES::INVALID , 0}, - }; - - auto genState = [this]( const Account* a, AES s, AES p ) { - Q_UNUSED(a) - - const ES newState = d_ptr->convertAccountEditState(s); - const ES oldState = d_ptr->convertAccountEditState(p); - - if (newState != oldState) - estates.setAt(oldState,estates[oldState]-1); - - estates.setAt(newState,estates[newState]+1); - - const ES oldGlobalState = s_CurrentState; - - s_CurrentState = estates[ES::INVALID] ? ES::INVALID: - estates[ES::UNSAVED] ? ES::UNSAVED: - ES::SAVED ; - - if (s_CurrentState != oldGlobalState) - emit editStateChanged(s_CurrentState, oldGlobalState); - - }; - - static bool isInit = false; - if (!isInit) { - isInit = true; - - for (const Account* a : d_ptr->m_lAccounts) { - genState(a,a->editState(),a->editState()); - } - - connect(this, &AccountModel::accountEditStateChanged, genState); - } - - - return s_CurrentState; -} - -///Client can call this to force subscribe/resubscribe to all buddies -void -AccountModel::subscribeToBuddies(const QString &accountId) -{ - Account* account = getById(accountId.toLatin1()); - if (account && account->protocol() == Account::Protocol::RING) { - const auto account_contacts = static_cast<QVector<QMap<QString, QString>>>(ConfigurationManager::instance().getContacts(accountId.toUtf8().constData())); - for (auto contact_info : account_contacts) { - PresenceManager::instance().subscribeBuddy(accountId, - contact_info["id"], - true); - } - } -} - -/***************************************************************************** - * * - * Getters * - * * - ****************************************************************************/ - -/** - * Get an account by its ID - * - * @note This method have O(N) complexity, but the average account count is low - * - * @param id The account identifier - * @param usePlaceHolder Return a placeholder for a future account instead of nullptr - * @return an account if it exist, a placeholder if usePlaceHolder==true or nullptr - */ -Account* AccountModel::getById(const QByteArray& id, bool usePlaceHolder) const -{ - if (id.isEmpty()) - return nullptr; - //This function use a loop as the expected size is < 5 - for (int i = 0; i < d_ptr->m_lAccounts.size(); i++) { - Account* acc = d_ptr->m_lAccounts[i]; - if (acc && !acc->isNew() && acc->id() == id) - return acc; - } - - //The account doesn't exist (yet) - if (usePlaceHolder) { - AccountPlaceHolder* ph = d_ptr->m_hsPlaceHolder[id]; - if (!ph) { - ph = new AccountPlaceHolder(id); - d_ptr->m_hsPlaceHolder[id] = ph; - } - return ph; - } - - return nullptr; -} - -///Get the account size -int AccountModel::size() const -{ - return d_ptr->m_lAccounts.size(); -} - -///Get data from the model -QVariant AccountModel::data ( const QModelIndex& idx, int role) const -{ - if (!idx.isValid() || idx.row() < 0 || idx.row() >= rowCount()) - return QVariant(); - - return d_ptr->m_lAccounts[idx.row()]->roleData(role); -} //data - -///Flags for "idx" -Qt::ItemFlags AccountModel::flags(const QModelIndex& idx) const -{ - if (idx.column() == 0) - return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; - return QAbstractItemModel::flags(idx); -} - -///Number of account -int AccountModel::rowCount(const QModelIndex& parentIdx) const -{ - return parentIdx.isValid() ? 0 : d_ptr->m_lAccounts.size(); -} - -Account* AccountModel::getAccountByModelIndex(const QModelIndex& item) const -{ - if (!item.isValid()) - return nullptr; - return d_ptr->m_lAccounts[item.row()]; -} - -///Generate an unique suffix to prevent multiple account from sharing alias -QString AccountModel::getSimilarAliasIndex(const QString& alias) -{ - auto& self = instance(); - - int count = 0; - foreach (Account* a, self.d_ptr->m_lAccounts) { - if (a->alias().left(alias.size()) == alias) - count++; - } - bool found = true; - do { - found = false; - foreach (Account* a, self.d_ptr->m_lAccounts) { - if (a->alias() == alias+QString(" (%1)").arg(count)) { - count++; - found = false; - break; - } - } - } while(found); - if (count) - return QString(" (%1)").arg(count); - return QString(); -} - -QList<Account*> AccountModel::getAccountsByProtocol( const Account::Protocol protocol ) const -{ - switch(protocol) { - case Account::Protocol::SIP: - return d_ptr->m_lSipAccounts; - case Account::Protocol::RING: - return d_ptr->m_lRingAccounts; - case Account::Protocol::COUNT__: - break; - } - - return {}; -} - -bool AccountModel::isPresenceEnabled() const -{ - foreach(Account* a, d_ptr->m_lAccounts) { - if (a->presenceEnabled()) - return true; - } - return false; -} - -bool AccountModel::isPresencePublishSupported() const -{ - foreach(Account* a,d_ptr->m_lAccounts) { - if (a->supportPresencePublish()) - return true; - } - return false; -} - -bool AccountModel::isPresenceSubscribeSupported() const -{ - foreach(Account* a,d_ptr->m_lAccounts) { - if (a->supportPresenceSubscribe()) - return true; - } - return false; -} - -bool AccountModel::isSipSupported() const -{ - return d_ptr->m_lSupportedProtocols[Account::Protocol::SIP]; -} - -bool AccountModel::isIP2IPSupported() const -{ - if (auto a = ip2ip()) - return a->isEnabled(); - return false; -} - -bool AccountModel::isRingSupported() const -{ - return d_ptr->m_lSupportedProtocols[Account::Protocol::RING]; -} - - -/***************************************************************************** - * * - * Setters * - * * - ****************************************************************************/ - -///Have a single place where m_lAccounts receive inserts -void AccountModelPrivate::insertAccount(Account* a, int idx) -{ - q_ptr->beginInsertRows(QModelIndex(), idx, idx); - m_lAccounts.insert(idx,a); - q_ptr->endInsertRows(); - - connect(a,&Account::editStateChanged, [a,this](const Account::EditState state, const Account::EditState previous) { - emit q_ptr->accountEditStateChanged(a, state, previous); - }); - - switch(a->protocol()) { - case Account::Protocol::SIP: - m_lSipAccounts << a; - break; - case Account::Protocol::RING: - m_lRingAccounts << a; - break; - case Account::Protocol::COUNT__: - break; - } -} - -void AccountModelPrivate::removeAccount(Account* account) -{ - const int aindex = m_lAccounts.indexOf(account); - - q_ptr->beginRemoveRows(QModelIndex(),aindex,aindex); - m_lAccounts.remove(aindex); - m_lDeletedAccounts << account->id(); - q_ptr->endRemoveRows(); - - m_pRemovedAccounts << account; - - switch(account->protocol()) { - case Account::Protocol::RING: - m_lRingAccounts.removeOne(account); - break; - case Account::Protocol::SIP: - m_lSipAccounts.removeOne(account); - break; - case Account::Protocol::COUNT__: - break; - } -} - -Account* AccountModel::add(const QString& alias, const Account::Protocol proto) -{ - Account* a = Account::buildNewAccountFromAlias(proto,alias); - connect(a,SIGNAL(changed(Account*)),d_ptr,SLOT(slotAccountChanged(Account*))); - d_ptr->insertAccount(a,d_ptr->m_lAccounts.size()); - connect(a,SIGNAL(presenceEnabledChanged(bool)),d_ptr,SLOT(slotAccountPresenceEnabledChanged(bool))); - //connect(a,SIGNAL(propertyChanged(Account*,QString,QString,QString)),d_ptr,SLOT(slotAccountChanged(Account*))); - - emit dataChanged(index(d_ptr->m_lAccounts.size()-1,0), index(d_ptr->m_lAccounts.size()-1,0)); - - if (d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel->setCurrentIndex(index(d_ptr->m_lAccounts.size()-1,0), QItemSelectionModel::ClearAndSelect); - } - - if (!a->isIp2ip()) - d_ptr->enableProtocol(proto); - -// Override ringtone path -#if defined(Q_OS_OSX) - QDir ringtonesDir(QCoreApplication::applicationDirPath()); - ringtonesDir.cdUp(); - ringtonesDir.cd("Resources/ringtones/"); - a->setRingtonePath(ringtonesDir.path()+"/default.wav"); -#endif - - emit accountAdded(a); - - editState(); - - return a; -} - -///Remove an account -void AccountModel::remove(Account* account) -{ - if (not account) { - return; - } - qDebug() << "Removing" << account->alias() << account->id(); - d_ptr->removeAccount(account); - emit accountRemoved(account); -} - -void AccountModel::remove(const QModelIndex& idx ) -{ - remove(getAccountByModelIndex(idx)); -} - -///Set model data -bool AccountModel::setData(const QModelIndex& idx, const QVariant& value, int role) -{ - if (idx.isValid() && idx.column() == 0 && role == Qt::CheckStateRole) { - const bool prevEnabled = d_ptr->m_lAccounts[idx.row()]->isEnabled(); - d_ptr->m_lAccounts[idx.row()]->setEnabled(value.toBool()); - emit dataChanged(idx, idx); - if (prevEnabled != value.toBool()) - emit accountEnabledChanged(d_ptr->m_lAccounts[idx.row()]); - emit dataChanged(idx, idx); - return true; - } - else if ( role == Qt::EditRole ) { - if (value.toString() != data(idx,Qt::EditRole)) { - d_ptr->m_lAccounts[idx.row()]->setAlias(value.toString()); - emit dataChanged(idx, idx); - } - } - return false; -} - - -/***************************************************************************** - * * - * Operator * - * * - ****************************************************************************/ - -///Get the account from its index -const Account* AccountModel::operator[] (int i) const -{ - return d_ptr->m_lAccounts[i]; -} - -///Get the account from its index -Account* AccountModel::operator[] (int i) -{ - return d_ptr->m_lAccounts[i]; -} - -///Get accoutn by id -Account* AccountModel::operator[] (const QByteArray& i) { - return getById(i); -} - -void AccountModel::add(Account* acc) -{ - d_ptr->insertAccount(acc,d_ptr->m_lAccounts.size()); -} - - -/***************************************************************************** - * * - * Drag and drop * - * * - ****************************************************************************/ - - -QStringList AccountModel::mimeTypes() const -{ - return d_ptr->m_lMimes; -} - -bool AccountModel::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) -{ - Q_UNUSED(action) - if(parent.isValid() || column > 0) { - qDebug() << "column invalid"; - return false; - } - - if (data->hasFormat(RingMimes::ACCOUNT)) { - int destinationRow = -1; - - if(row < 0) { - //drop on top - destinationRow = d_ptr->m_lAccounts.size() - 1; - } - else if(row >= d_ptr->m_lAccounts.size()) { - destinationRow = 0; - } - else { - destinationRow = row; - } - - Account* dest = getById(data->data(RingMimes::ACCOUNT)); - if (!dest) - return false; - - const QModelIndex accIdx = dest->index(); - - beginRemoveRows(QModelIndex(), accIdx.row(), accIdx.row()); - Account* acc = d_ptr->m_lAccounts[accIdx.row()]; - d_ptr->m_lAccounts.removeAt(accIdx.row()); - endRemoveRows(); - - d_ptr->insertAccount(acc,destinationRow); - - d_ptr->m_pSelectionModel->setCurrentIndex(index(destinationRow), QItemSelectionModel::ClearAndSelect); - - return true; - } - - return false; -} - -QMimeData* AccountModel::mimeData(const QModelIndexList& indexes) const -{ - QMimeData* mMimeData = new QMimeData(); - - for (const QModelIndex& index : indexes) { - if (index.isValid()) { - mMimeData->setData(RingMimes::ACCOUNT, index.data((int)Account::Role::Id).toByteArray()); - } - } - - return mMimeData; -} - -Qt::DropActions AccountModel::supportedDragActions() const -{ - return Qt::MoveAction | Qt::TargetMoveAction; -} - -Qt::DropActions AccountModel::supportedDropActions() const -{ - return Qt::MoveAction | Qt::TargetMoveAction; -} - -void AccountModel::slotConnectivityChanged() -{ - ConfigurationManager::instance().connectivityChanged(); -} - -Account* AccountModel::findPlaceHolder(const QByteArray& accountId) const -{ - auto iter = d_ptr->m_hsPlaceHolder.find(accountId); - if (iter != d_ptr->m_hsPlaceHolder.end()) - return *iter; - return nullptr; -} - -Account* AccountModel::findAccountIf(const std::function<bool(const Account&)>& pred) const -{ - auto iter = std::find_if(std::begin(d_ptr->m_lAccounts), std::end(d_ptr->m_lAccounts), - [&](Account* acc){ return acc and pred(*acc); }); - if (iter != std::end(d_ptr->m_lAccounts)) - return *iter; - return nullptr; -} - -#include <accountmodel.moc> diff --git a/src/accountmodel.h b/src/accountmodel.h deleted file mode 100644 index 094f7bfaea239369ce0d1cac7b58c64a30a9c52a..0000000000000000000000000000000000000000 --- a/src/accountmodel.h +++ /dev/null @@ -1,168 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <functional> - -#include <QtCore/QVector> -#include <QtCore/QStringList> -#include <QtCore/QAbstractListModel> - -#include "account.h" -#include "typedefs.h" - -//Private -class AccountModelPrivate; - -///AccountList: List of all daemon accounts -class LIB_EXPORT AccountModel : public QAbstractListModel { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - -public: - Q_PROPERTY(Account* ip2ip READ ip2ip ) - Q_PROPERTY(bool presenceEnabled READ isPresenceEnabled ) - Q_PROPERTY(bool presencePublishSupported READ isPresencePublishSupported ) - Q_PROPERTY(bool presenceSubscribeSupported READ isPresenceSubscribeSupported ) - Q_PROPERTY(bool isSipSupported READ isSipSupported NOTIFY supportedProtocolsChanged) - Q_PROPERTY(bool isIP2IPSupported READ isIP2IPSupported NOTIFY supportedProtocolsChanged) - Q_PROPERTY(bool isRingSupported READ isRingSupported NOTIFY supportedProtocolsChanged) - Q_PROPERTY(Account* selectedAccount READ selectedAccount ) - Q_PROPERTY(Account* userChosenAccount READ userChosenAccount WRITE setUserChosenAccount) - - friend class AccountPrivate; - - /// @enum Global saving state to be used when using a single saving mechanism for all accounts at once - enum class EditState { - SAVED = 0, /*!< Everything is ok, nothing has changed */ - UNSAVED = 1, /*!< There is changes ready to be saved */ - INVALID = 2, /*!< There is changes, but they would create an invalid state */ - COUNT__ - }; - - //Singleton - static AccountModel& instance(); - - //Getters - Q_INVOKABLE Account* getById ( const QByteArray& id, bool ph = false) const; - int size ( ) const; - Account* getAccountByModelIndex ( const QModelIndex& item ) const; - Q_INVOKABLE static QString getSimilarAliasIndex ( const QString& alias ) ; - Account* ip2ip ( ) const; - QList<Account*> getAccountsByProtocol ( const Account::Protocol protocol ) const; - bool isPresenceEnabled ( ) const; - bool isPresencePublishSupported ( ) const; - bool isPresenceSubscribeSupported( ) const; - bool isSipSupported ( ) const; - bool isIP2IPSupported ( ) const; - bool isRingSupported ( ) const; - EditState editState ( ) const; - void subscribeToBuddies (const QString &accountID ) ; - Account* selectedAccount ( ) const; - QList<Account*> accountsToMigrate ( ) const; - QVector<QMap<QString, QString>> getContacts (const Account* account ) const; - - QItemSelectionModel* selectionModel ( ) const; - Account* userChosenAccount ( ) const; - QItemSelectionModel* userSelectionModel ( ) const; - - //Abstract model accessors - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QHash<int,QByteArray> roleNames ( ) const override; - virtual QMimeData* mimeData ( const QModelIndexList &indexes ) const override; - virtual QStringList mimeTypes ( ) const override; - virtual bool dropMimeData( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; - virtual Qt::DropActions supportedDragActions() const override; - virtual Qt::DropActions supportedDropActions() const override; - - //Mutators - Q_INVOKABLE Account* add ( const QString& alias, const Account::Protocol protocol = Account::Protocol::SIP); - Q_INVOKABLE void remove ( Account* account ); - void remove ( const QModelIndex& index ); - void save ( ); - Q_INVOKABLE void cancel ( ); - int exportAccounts(const QStringList& accountIDs, const QString& filePath, const QString& password); - int importAccounts(const QString& filePath, const QString& password); - void setUserChosenAccount(Account* account); - - //Operators - Account* operator[] (int i) ; - Account* operator[] (const QByteArray& i) ; - const Account* operator[] (int i) const; - - //Helpers - Account* findPlaceHolder(const QByteArray& accountId) const; - Account* findAccountIf(const std::function<bool(const Account&)>& pred) const; - -private: - //Constructors & Destructors - explicit AccountModel (); - virtual ~AccountModel(); - - //Helpers - void add(Account* acc); - - AccountModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(AccountModel) - -public Q_SLOTS: - void update (); - void updateAccounts (); - void registerAllAccounts(); - bool moveUp (); - bool moveDown (); - ///Notifies the Ring daemon that the connectivity (network status) has changed - void slotConnectivityChanged(); - -Q_SIGNALS: - ///The account list changed - void accountListUpdated( ); - ///Emitted when an account enable attribute change - void accountEnabledChanged( Account* source ); - ///Emitted when the default account change - void defaultAccountChanged( Account* a ); - ///Emitted when one account registration state change - void registrationChanged(Account* a, bool registration ); - ///Emitted when the network is down - void badGateway( ); - ///Emitted when a new voice mail is available - void voiceMailNotify(Account* account, int count ); - ///Propagate Account::presenceEnabledChanged - void presenceEnabledChanged(bool isPresent ); - ///An account has been removed - void accountRemoved(Account* account ); - ///An account has been added - void accountAdded(Account* account ); - ///Emitted when an account using a previously unsupported protocol is added - void supportedProtocolsChanged( ); - ///Emitted when an account state change - void accountStateChanged ( Account* account, const Account::RegistrationState state); - ///Emitted when an account edit state change - void accountEditStateChanged(Account* account, const Account::EditState state, const Account::EditState prev); - ///The global AccountModel edit state changed - void editStateChanged(const EditState state, const EditState previous) const; - /// A list of contacts has been obtained. - void contactsList(Account *account); -}; -Q_DECLARE_METATYPE(AccountModel*) diff --git a/src/api/avmodel.h b/src/api/avmodel.h index 4cdbcd0b254ee04a5cc05aa240ea435d8ef676f8..7429fc10249be42ce60e5b34c2fb1b28ddf71064 100644 --- a/src/api/avmodel.h +++ b/src/api/avmodel.h @@ -196,6 +196,16 @@ public: * @param audioOnly */ std::string startLocalRecorder(const bool& audioOnly) const; + /** + * Get the current recording path + * @return recording path + */ + std::string getRecordPath() const; + /** + * Sets the recording path + * @param recording path + */ + void setRecordPath(const std::string& path) const; /** * Start preview renderer. This will start the camera @@ -240,8 +250,6 @@ public: */ video::RenderedDevice getCurrentRenderedDevice(const std::string& call_id) const; - // TODO remove this, this is just to avoid dual rendering. - void deactivateOldVideoModels(); /** * set to true to receive AVFrames from render */ diff --git a/src/api/newcallmodel.h b/src/api/newcallmodel.h index 0a19b370dce87e7c12717c975913e39d9a9ccf3b..b5f0b95516b90fba748a51de8afe7108944ffb9b 100644 --- a/src/api/newcallmodel.h +++ b/src/api/newcallmodel.h @@ -174,11 +174,6 @@ public: * Not implemented yet */ void removeParticipant(const std::string& callId, const std::string& participant) const; - /** - * @param callId - * @return the renderer linked to a call - */ - Video::Renderer* getRenderer(const std::string& callId) const; /** * @param callId * @return a human readable call duration (M:ss) diff --git a/src/audio/alsapluginmodel.cpp b/src/audio/alsapluginmodel.cpp deleted file mode 100644 index 63b36a3813a8353423f322a2032b4415e10c08ee..0000000000000000000000000000000000000000 --- a/src/audio/alsapluginmodel.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "alsapluginmodel.h" - -//Qt -#include <QtCore/QItemSelectionModel> - -//Ring -#include "dbus/configurationmanager.h" - -class AlsaPluginModelPrivate final : public QObject -{ - Q_OBJECT -public: - AlsaPluginModelPrivate(Audio::AlsaPluginModel* parent); - QStringList m_lDeviceList; - mutable QItemSelectionModel* m_pSelectionModel; - -private: - Audio::AlsaPluginModel* q_ptr; - -public Q_SLOTS: - void setCurrentPlugin(const QModelIndex& idx); -}; - -AlsaPluginModelPrivate::AlsaPluginModelPrivate(Audio::AlsaPluginModel* parent) : q_ptr(parent), -m_pSelectionModel(nullptr) -{ - -} - -///Constructor -Audio::AlsaPluginModel::AlsaPluginModel(const QObject* parent) : QAbstractListModel(const_cast<QObject*>(parent)), -d_ptr(new AlsaPluginModelPrivate(this)) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - d_ptr->m_lDeviceList = configurationManager.getAudioPluginList(); -} - -///Destructor -Audio::AlsaPluginModel::~AlsaPluginModel() -{ - -} - -QHash<int,QByteArray> Audio::AlsaPluginModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -///Re-implement QAbstractListModel data -QVariant Audio::AlsaPluginModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - switch(role) { - case Qt::DisplayRole: - return d_ptr->m_lDeviceList[index.row()]; - }; - return QVariant(); -} - -///Re-implement QAbstractListModel rowCount -int Audio::AlsaPluginModel::rowCount( const QModelIndex& parent ) const -{ - if (parent.isValid()) - return 0; - return d_ptr->m_lDeviceList.size(); -} - -///Re-implement QAbstractListModel flags -Qt::ItemFlags Audio::AlsaPluginModel::flags( const QModelIndex& index ) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -///Setting data is disabled -bool Audio::AlsaPluginModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QItemSelectionModel* Audio::AlsaPluginModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<Audio::AlsaPluginModel*>(this)); - - d_ptr->m_pSelectionModel->setCurrentIndex(currentPlugin(), QItemSelectionModel::ClearAndSelect); - - connect(d_ptr->m_pSelectionModel, &QItemSelectionModel::currentChanged, d_ptr.data(), &AlsaPluginModelPrivate::setCurrentPlugin); - } - - return d_ptr->m_pSelectionModel; -} - -///Return the current index -QModelIndex Audio::AlsaPluginModel::currentPlugin() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const int idx = d_ptr->m_lDeviceList.indexOf(configurationManager.getCurrentAudioOutputPlugin()); - qDebug() << "Invalid current audio plugin"; - if (idx == -1) - return QModelIndex(); - else - return index(idx,0,QModelIndex()); -} - -///Set the current index -void AlsaPluginModelPrivate::setCurrentPlugin(const QModelIndex& idx) -{ - if (!idx.isValid()) - return; - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setAudioPlugin(m_lDeviceList[idx.row()]); -} - -///Reload to current daemon state -void Audio::AlsaPluginModel::reload() -{ - const int currentRow = selectionModel()->currentIndex().row(); - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - beginResetModel(); - d_ptr->m_lDeviceList = configurationManager.getAudioPluginList(); - endResetModel(); - emit layoutChanged(); - emit dataChanged(index(0,0),index(d_ptr->m_lDeviceList.size()-1,0)); - - // Restore the selection - d_ptr->m_pSelectionModel->setCurrentIndex(index(currentRow,0), QItemSelectionModel::ClearAndSelect); - -} - -#include <alsapluginmodel.moc> diff --git a/src/audio/alsapluginmodel.h b/src/audio/alsapluginmodel.h deleted file mode 100644 index fbc6a6b310c30e236e1b2afcd93b0cb2aab0a62b..0000000000000000000000000000000000000000 --- a/src/audio/alsapluginmodel.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -//Qt -#include <QtCore/QStringList> - -//Ring -#include <typedefs.h> - -class AlsaPluginModelPrivate; -class QItemSelectionModel; - -namespace Audio { - -class LIB_EXPORT AlsaPluginModel : public QAbstractListModel { - Q_OBJECT -public: - explicit AlsaPluginModel(const QObject* parent); - virtual ~AlsaPluginModel(); - - //Models function - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getters - QModelIndex currentPlugin() const; - QItemSelectionModel* selectionModel() const; - - //Mutator - void reload(); - -private: - QScopedPointer<AlsaPluginModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(AlsaPluginModel) -}; - -} - diff --git a/src/audio/inputdevicemodel.cpp b/src/audio/inputdevicemodel.cpp deleted file mode 100644 index 25954c00dc2b048295154603337a8fa181aafa01..0000000000000000000000000000000000000000 --- a/src/audio/inputdevicemodel.cpp +++ /dev/null @@ -1,167 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "inputdevicemodel.h" - -//Qt -#include <QtCore/QItemSelectionModel> - -//Ring -#include "dbus/configurationmanager.h" -#include "settings.h" - -class InputDeviceModelPrivate final : public QObject -{ - Q_OBJECT -public: - InputDeviceModelPrivate(Audio::InputDeviceModel* parent); - QStringList m_lDeviceList; - mutable QItemSelectionModel* m_pSelectionModel; - QModelIndex currentDevice() const; - -private: - Audio::InputDeviceModel* q_ptr; - -public Q_SLOTS: - void setCurrentDevice(const QModelIndex& index); -}; - -InputDeviceModelPrivate::InputDeviceModelPrivate(Audio::InputDeviceModel* parent) : q_ptr(parent), - m_pSelectionModel(nullptr) -{ - -} - -QHash<int,QByteArray> Audio::InputDeviceModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -///Constructor -Audio::InputDeviceModel::InputDeviceModel(const QObject* parent) : QAbstractListModel(const_cast<QObject*>(parent)), -d_ptr(new InputDeviceModelPrivate(this)) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - d_ptr->m_lDeviceList = configurationManager.getAudioInputDeviceList (); - connect(&configurationManager, SIGNAL(audioDeviceEvent()), this, SLOT(reload())); -} - -///Destructor -Audio::InputDeviceModel::~InputDeviceModel() -{ - -} - -///Re-implement QAbstractListModel data -QVariant Audio::InputDeviceModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - switch(role) { - case Qt::DisplayRole: - if (index.row() < d_ptr->m_lDeviceList.size()) - return d_ptr->m_lDeviceList[index.row()]; - }; - return QVariant(); -} - -///Re-implement QAbstractListModel rowCount -int Audio::InputDeviceModel::rowCount( const QModelIndex& parent ) const -{ - if (parent.isValid()) - return 0; - return d_ptr->m_lDeviceList.size(); -} - -///Re-implement QAbstractListModel flags -Qt::ItemFlags Audio::InputDeviceModel::flags( const QModelIndex& index ) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -///This model does not support setting data -bool Audio::InputDeviceModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QItemSelectionModel* Audio::InputDeviceModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<Audio::InputDeviceModel*>(this)); - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList currentDevices = configurationManager.getCurrentAudioDevicesIndex(); - const auto input_idx = static_cast<int>(Settings::DeviceIndex::INPUT); - if (input_idx < currentDevices.size()) { - const int idx = currentDevices[input_idx].toInt(); - if (idx < d_ptr->m_lDeviceList.size()) - d_ptr->m_pSelectionModel->setCurrentIndex(index(idx,0), QItemSelectionModel::ClearAndSelect); - } - - connect(d_ptr->m_pSelectionModel, &QItemSelectionModel::currentChanged, d_ptr.data(), &InputDeviceModelPrivate::setCurrentDevice); - } - - return d_ptr->m_pSelectionModel; -} - -///Return the current ringtone device -QModelIndex InputDeviceModelPrivate::currentDevice() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList currentDevices = configurationManager.getCurrentAudioDevicesIndex(); - const auto input_idx = static_cast<int>(Audio::Settings::DeviceIndex::INPUT); - if (input_idx < currentDevices.size()) { - const int idx = currentDevices[input_idx].toInt(); - if (idx < m_lDeviceList.size()) - return q_ptr->index(idx,0); - } - return {}; -} - -///Set the current input device -void InputDeviceModelPrivate::setCurrentDevice(const QModelIndex& index) -{ - if (index.isValid() and index != currentDevice()) { - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setAudioInputDevice(index.row()); - } -} - -///Reload input device list -void Audio::InputDeviceModel::reload() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - beginResetModel(); - d_ptr->m_lDeviceList = configurationManager.getAudioInputDeviceList (); - endResetModel(); - - // Restore the selection - selectionModel()->setCurrentIndex(d_ptr->currentDevice(), QItemSelectionModel::ClearAndSelect); -} - -#include <inputdevicemodel.moc> diff --git a/src/audio/inputdevicemodel.h b/src/audio/inputdevicemodel.h deleted file mode 100644 index 59be81093730ff93f1461885d069654680699ed7..0000000000000000000000000000000000000000 --- a/src/audio/inputdevicemodel.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -//Qt -#include <QtCore/QStringList> -class QItemSelectionModel; - -//Ring -#include <typedefs.h> - -class InputDeviceModelPrivate; - -namespace Audio { - -class LIB_EXPORT InputDeviceModel : public QAbstractListModel { - Q_OBJECT -public: - explicit InputDeviceModel(const QObject* parent); - virtual ~InputDeviceModel(); - - //Models function - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getters - QItemSelectionModel* selectionModel() const; - -public Q_SLOTS: - void reload(); - -private: - QScopedPointer<InputDeviceModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(InputDeviceModel) -}; - -} - diff --git a/src/audio/managermodel.cpp b/src/audio/managermodel.cpp deleted file mode 100644 index ce88b00894dd3e0eb6f08daa9c093d4bdce87633..0000000000000000000000000000000000000000 --- a/src/audio/managermodel.cpp +++ /dev/null @@ -1,191 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "managermodel.h" - -//Qt -#include <QtCore/QItemSelectionModel> - -//Ring -#include "dbus/configurationmanager.h" -#include "settings.h" - -class ManagerModelPrivate final : public QObject -{ - Q_OBJECT -public: - ManagerModelPrivate(Audio::ManagerModel* parent); - class ManagerName { - public: - constexpr static const char* PULSEAUDIO = "pulseaudio"; - constexpr static const char* ALSA = "alsa" ; - constexpr static const char* JACK = "jack" ; - }; - - QStringList m_lDeviceList; - QList<Audio::ManagerModel::Manager> m_lSupportedManagers; - mutable QItemSelectionModel* m_pSelectionModel; - -private: - Audio::ManagerModel* q_ptr; - -public Q_SLOTS: - void slotSelectionChanged(const QModelIndex& idx); -}; - -ManagerModelPrivate::ManagerModelPrivate(Audio::ManagerModel* parent) : q_ptr(parent), - m_pSelectionModel(nullptr) -{ - -} - -///Constructor -Audio::ManagerModel::ManagerModel(const QObject* parent) : QAbstractListModel(const_cast<QObject*>(parent)), -d_ptr(new ManagerModelPrivate(this)) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList managers = configurationManager.getSupportedAudioManagers(); - foreach(const QString& m,managers) { - if (m == ManagerModelPrivate::ManagerName::PULSEAUDIO) { - d_ptr->m_lSupportedManagers << Manager::PULSE; - d_ptr->m_lDeviceList << "Pulse Audio"; - } - else if (m == ManagerModelPrivate::ManagerName::ALSA) { - d_ptr->m_lSupportedManagers << Manager::ALSA; - d_ptr->m_lDeviceList<< "ALSA"; - } - else if (m == ManagerModelPrivate::ManagerName::JACK) { - d_ptr->m_lSupportedManagers << Manager::JACK; - d_ptr->m_lDeviceList<< "Jack"; - } - else - qDebug() << "Unsupported audio manager" << m; - } -} - -///Destructor -Audio::ManagerModel::~ManagerModel() -{ - d_ptr->m_lDeviceList.clear(); -} - -QHash<int,QByteArray> Audio::ManagerModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -///Re-implement QAbstractListModel data -QVariant Audio::ManagerModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - switch(role) { - case Qt::DisplayRole: - return d_ptr->m_lDeviceList[index.row()]; - }; - return QVariant(); -} - -///Re-implement QAbstractListModel rowCount -int Audio::ManagerModel::rowCount( const QModelIndex& parent ) const -{ - if (parent.isValid()) - return 0; - return d_ptr->m_lDeviceList.size(); -} - -///Re-implement QAbstractListModel flags -Qt::ItemFlags Audio::ManagerModel::flags( const QModelIndex& index ) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -///This model is read only -bool Audio::ManagerModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -/** - * This model allow automatic synchronization of the audio manager - */ -QItemSelectionModel* Audio::ManagerModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<Audio::ManagerModel*>(this)); - connect(d_ptr->m_pSelectionModel,&QItemSelectionModel::currentChanged,d_ptr.data(),&ManagerModelPrivate::slotSelectionChanged); - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QString manager = configurationManager.getAudioManager(); - - if (manager == ManagerModelPrivate::ManagerName::PULSEAUDIO) - d_ptr->m_pSelectionModel->setCurrentIndex( index((int)Manager::PULSE,0) , QItemSelectionModel::ClearAndSelect ); - else if (manager == ManagerModelPrivate::ManagerName::ALSA) - d_ptr->m_pSelectionModel->setCurrentIndex( index((int)Manager::ALSA,0) , QItemSelectionModel::ClearAndSelect ); - else if (manager == ManagerModelPrivate::ManagerName::JACK) - d_ptr->m_pSelectionModel->setCurrentIndex( index((int)Manager::JACK,0) , QItemSelectionModel::ClearAndSelect ); - } - - return d_ptr->m_pSelectionModel; -} - -void ManagerModelPrivate::slotSelectionChanged(const QModelIndex& idx) -{ - if (!idx.isValid()) - return; - - bool ret = true; - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - switch (m_lSupportedManagers[idx.row()]) { - case Audio::ManagerModel::Manager::PULSE: - ret = configurationManager.setAudioManager(ManagerModelPrivate::ManagerName::PULSEAUDIO); - Audio::Settings::instance().reload(); - break; - case Audio::ManagerModel::Manager::ALSA: - ret = configurationManager.setAudioManager(ManagerModelPrivate::ManagerName::ALSA); - Audio::Settings::instance().reload(); - break; - case Audio::ManagerModel::Manager::JACK: - ret = configurationManager.setAudioManager(ManagerModelPrivate::ManagerName::JACK); - Audio::Settings::instance().reload(); - break; - case Audio::ManagerModel::Manager::ERROR: - break; - }; - if (!ret) { - emit q_ptr->currentManagerChanged(q_ptr->currentManager()); - } - return; -} - -Audio::ManagerModel::Manager Audio::ManagerModel::currentManager() const -{ - const int idx = selectionModel()->currentIndex().row(); - return idx>=0 ? d_ptr->m_lSupportedManagers[idx] : Manager::ERROR; -} - -#include <managermodel.moc> diff --git a/src/audio/managermodel.h b/src/audio/managermodel.h deleted file mode 100644 index 5f0fa321d23e40bbf4fe297df2dba7680809e15e..0000000000000000000000000000000000000000 --- a/src/audio/managermodel.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -//Qt -#include <QtCore/QStringList> -class QItemSelectionModel; - -//Ring -#include <typedefs.h> - -class ManagerModelPrivate; - -namespace Audio { - -class LIB_EXPORT ManagerModel : public QAbstractListModel { - Q_OBJECT -public: - - enum class Manager { - ALSA =0, - PULSE=1, - JACK =2, - ERROR=3, - }; - explicit ManagerModel(const QObject* parent); - virtual ~ManagerModel(); - - //Models function - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getters - QItemSelectionModel* selectionModel() const; - Manager currentManager() const; - -Q_SIGNALS: - void currentManagerChanged(Manager); - -private: - QScopedPointer<ManagerModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(ManagerModel) -}; - -} - diff --git a/src/audio/outputdevicemodel.cpp b/src/audio/outputdevicemodel.cpp deleted file mode 100644 index 36613930d920fb09385fd99888e61935069abeb5..0000000000000000000000000000000000000000 --- a/src/audio/outputdevicemodel.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "outputdevicemodel.h" - -//Qt -#include <QtCore/QItemSelectionModel> - -//Ring -#include "dbus/configurationmanager.h" -#include "dbus/callmanager.h" -#include "settings.h" - -class OutputDeviceModelPrivate final : public QObject -{ - Q_OBJECT -public: - OutputDeviceModelPrivate(Audio::OutputDeviceModel* parent); - QStringList m_lDeviceList; - mutable QItemSelectionModel* m_pSelectionModel; - QModelIndex currentDevice() const; - -private: - Audio::OutputDeviceModel* q_ptr; - -public Q_SLOTS: - void setCurrentDevice(const QModelIndex& index); -}; - - -OutputDeviceModelPrivate::OutputDeviceModelPrivate(Audio::OutputDeviceModel* parent) : q_ptr(parent), - m_pSelectionModel(nullptr) -{ - -} - -///Constructor -Audio::OutputDeviceModel::OutputDeviceModel(const QObject* parent) : QAbstractListModel(const_cast<QObject*>(parent)), -d_ptr(new OutputDeviceModelPrivate(this)) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - d_ptr->m_lDeviceList = configurationManager.getAudioOutputDeviceList(); - connect(&configurationManager, SIGNAL(audioDeviceEvent()), this, SLOT(reload())); -} - -///Destructor -Audio::OutputDeviceModel::~OutputDeviceModel() -{ - -} - -QHash<int,QByteArray> Audio::OutputDeviceModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -///Re-implement QAbstractListModel data -QVariant Audio::OutputDeviceModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - switch(role) { - case Qt::DisplayRole: - if (index.row() < d_ptr->m_lDeviceList.size()) - return d_ptr->m_lDeviceList[index.row()]; - }; - return QVariant(); -} - -///Re-implement QAbstractListModel rowCount -int Audio::OutputDeviceModel::rowCount( const QModelIndex& parent ) const -{ - if (parent.isValid()) - return 0; - return d_ptr->m_lDeviceList.size(); -} - -///Re-implement QAbstractListModel flags -Qt::ItemFlags Audio::OutputDeviceModel::flags( const QModelIndex& index ) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -///This model is read only -bool Audio::OutputDeviceModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QItemSelectionModel* Audio::OutputDeviceModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<Audio::OutputDeviceModel*>(this)); - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList currentDevices = configurationManager.getCurrentAudioDevicesIndex(); - const auto output_idx = static_cast<int>(Audio::Settings::DeviceIndex::OUTPUT); - if (output_idx < currentDevices.size()) { - const int idx = currentDevices[output_idx].toInt(); - if (idx < d_ptr->m_lDeviceList.size()) - d_ptr->m_pSelectionModel->setCurrentIndex(index(idx,0), QItemSelectionModel::ClearAndSelect); - } - - connect(d_ptr->m_pSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), d_ptr.data(), SLOT(setCurrentDevice(QModelIndex))); - } - - return d_ptr->m_pSelectionModel; -} - -///Return the current ringtone device -QModelIndex OutputDeviceModelPrivate::currentDevice() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList currentDevices = configurationManager.getCurrentAudioDevicesIndex(); - const auto output_idx = static_cast<int>(Audio::Settings::DeviceIndex::OUTPUT); - if (output_idx < currentDevices.size()) { - const int idx = currentDevices[output_idx].toInt(); - if (idx < m_lDeviceList.size()) - return q_ptr->index(idx,0); - } - return {}; -} - -///Set the current output device -void OutputDeviceModelPrivate::setCurrentDevice(const QModelIndex& index) -{ - if (index.isValid() and index != currentDevice()) { - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setAudioOutputDevice(index.row()); - } -} - -///reload output devices list -void Audio::OutputDeviceModel::reload() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - beginResetModel(); - d_ptr->m_lDeviceList = configurationManager.getAudioOutputDeviceList(); - endResetModel(); - - // Restore the selection - selectionModel()->setCurrentIndex(d_ptr->currentDevice(), QItemSelectionModel::ClearAndSelect); - -} - -void Audio::OutputDeviceModel::playDTMF(const QString& str) -{ - Q_NOREPLY CallManager::instance().playDTMF(str); -} - - -#include <outputdevicemodel.moc> diff --git a/src/audio/outputdevicemodel.h b/src/audio/outputdevicemodel.h deleted file mode 100644 index f9c0328b9c1329ad063b6d02187fe751c6b0c9d3..0000000000000000000000000000000000000000 --- a/src/audio/outputdevicemodel.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -//Qt -#include <QtCore/QStringList> -class QItemSelectionModel; - -//Ring -#include <typedefs.h> - -class OutputDeviceModelPrivate; - -namespace Audio { - -class LIB_EXPORT OutputDeviceModel : public QAbstractListModel { - Q_OBJECT -public: - explicit OutputDeviceModel(const QObject* parent); - virtual ~OutputDeviceModel(); - - //Models function - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getters - QItemSelectionModel* selectionModel() const; - - //Static methods - static void playDTMF(const QString& str); - -public Q_SLOTS: - void reload(); - -private: - QScopedPointer<OutputDeviceModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(OutputDeviceModel) -}; - -} - diff --git a/src/audio/ringtonedevicemodel.cpp b/src/audio/ringtonedevicemodel.cpp deleted file mode 100644 index d2e64be2a44d8b7b5ca1f077bb7390fe68f2e408..0000000000000000000000000000000000000000 --- a/src/audio/ringtonedevicemodel.cpp +++ /dev/null @@ -1,168 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "ringtonedevicemodel.h" - -//Qt -#include <QtCore/QItemSelectionModel> - -//Ring -#include "dbus/configurationmanager.h" -#include "settings.h" - -class RingtoneDeviceModelPrivate final : public QObject -{ - Q_OBJECT -public: - RingtoneDeviceModelPrivate(Audio::RingtoneDeviceModel* parent); - QStringList m_lDeviceList; - mutable QItemSelectionModel* m_pSelectionModel; - QModelIndex currentDevice() const; - -private: - Audio::RingtoneDeviceModel* q_ptr; - -public Q_SLOTS: - void setCurrentDevice(const QModelIndex& index); -}; - -RingtoneDeviceModelPrivate::RingtoneDeviceModelPrivate(Audio::RingtoneDeviceModel* parent) : q_ptr(parent), -m_pSelectionModel(nullptr) -{ - -} - -///Constructor -Audio::RingtoneDeviceModel::RingtoneDeviceModel(const QObject* parent) : QAbstractListModel(const_cast<QObject*>(parent)), -d_ptr(new RingtoneDeviceModelPrivate(this)) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - d_ptr->m_lDeviceList = configurationManager.getAudioOutputDeviceList(); - connect(&configurationManager, SIGNAL(audioDeviceEvent()), this, SLOT(reload())); -} - -///Destructor -Audio::RingtoneDeviceModel::~RingtoneDeviceModel() -{ - -} - -QHash<int,QByteArray> Audio::RingtoneDeviceModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -///Re-implement QAbstractListModel data -QVariant Audio::RingtoneDeviceModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - switch(role) { - case Qt::DisplayRole: - if (index.row() < d_ptr->m_lDeviceList.size()) - return d_ptr->m_lDeviceList[index.row()]; - }; - return QVariant(); -} - -///Re-implement QAbstractListModel rowCount -int Audio::RingtoneDeviceModel::rowCount( const QModelIndex& parent ) const -{ - if (parent.isValid()) - return 0; - return d_ptr->m_lDeviceList.size(); -} - -///Re-implement QAbstractListModel flags -Qt::ItemFlags Audio::RingtoneDeviceModel::flags( const QModelIndex& index ) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -///RingtoneDeviceModel is read only -bool Audio::RingtoneDeviceModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QItemSelectionModel* Audio::RingtoneDeviceModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<Audio::RingtoneDeviceModel*>(this)); - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList currentDevices = configurationManager.getCurrentAudioDevicesIndex(); - const auto ringtone_idx = static_cast<int>(Audio::Settings::DeviceIndex::RINGTONE); - if (ringtone_idx < currentDevices.size()) { - const int idx = currentDevices[ringtone_idx].toInt(); - if (idx < d_ptr->m_lDeviceList.size()) - d_ptr->m_pSelectionModel->setCurrentIndex(index(idx,0), QItemSelectionModel::ClearAndSelect); - } - - connect(d_ptr->m_pSelectionModel, SIGNAL(currentChanged(QModelIndex,QModelIndex)), d_ptr.data(), SLOT(setCurrentDevice(QModelIndex))); - } - - return d_ptr->m_pSelectionModel; -} - -///Return the current ringtone device -QModelIndex RingtoneDeviceModelPrivate::currentDevice() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - const QStringList currentDevices = configurationManager.getCurrentAudioDevicesIndex(); - const auto ringtone_idx = static_cast<int>(Audio::Settings::DeviceIndex::RINGTONE); - if (ringtone_idx < currentDevices.size()) { - const int idx = currentDevices[ringtone_idx].toInt(); - if (idx < m_lDeviceList.size()) - return q_ptr->index(idx,0); - } - return {}; -} - -///Set the current ringtone device -void RingtoneDeviceModelPrivate::setCurrentDevice(const QModelIndex& index) -{ - if (index.isValid() and index != currentDevice()) { - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setAudioRingtoneDevice(index.row()); - } -} - -///Reload ringtone device list -void Audio::RingtoneDeviceModel::reload() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - beginResetModel(); - d_ptr->m_lDeviceList = configurationManager.getAudioOutputDeviceList(); - endResetModel(); - - // Restore the selection - selectionModel()->setCurrentIndex(d_ptr->currentDevice(), QItemSelectionModel::ClearAndSelect); - -} - -#include <ringtonedevicemodel.moc> diff --git a/src/audio/ringtonedevicemodel.h b/src/audio/ringtonedevicemodel.h deleted file mode 100644 index c347227e9aa5bb0494f0d6511f05fdd6bee9da12..0000000000000000000000000000000000000000 --- a/src/audio/ringtonedevicemodel.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -//Qt -#include <QtCore/QStringList> - -//Ring -#include <typedefs.h> - -class RingtoneDeviceModelPrivate; -class QItemSelectionModel; - -namespace Audio { - -class LIB_EXPORT RingtoneDeviceModel: public QAbstractListModel { - Q_OBJECT -public: - explicit RingtoneDeviceModel(const QObject* parent); - virtual ~RingtoneDeviceModel(); - - //Models function - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getters - QItemSelectionModel* selectionModel() const; - -public Q_SLOTS: - void reload(); - -private: - QScopedPointer<RingtoneDeviceModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(RingtoneDeviceModel) -}; - -} - diff --git a/src/audio/settings.cpp b/src/audio/settings.cpp deleted file mode 100644 index 10d288550f8d1a1a8e40172d8b37f089b1996f2b..0000000000000000000000000000000000000000 --- a/src/audio/settings.cpp +++ /dev/null @@ -1,255 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "settings.h" - -//Qt include -#include <QUrl> - -//Ring -#include "dbus/configurationmanager.h" -#include "dbus/callmanager.h" -#include "ringtonedevicemodel.h" -#include "alsapluginmodel.h" -#include "managermodel.h" -#include "outputdevicemodel.h" -#include "inputdevicemodel.h" - -namespace Audio { -class SettingsPrivate final : public QObject -{ - Q_OBJECT -public: - SettingsPrivate(Audio::Settings* parent); - - //Attributes - mutable Audio::AlsaPluginModel* m_pAlsaPluginModel ; - mutable Audio::InputDeviceModel* m_pInputDeviceModel ; - mutable Audio::OutputDeviceModel* m_pOutputDeviceModel ; - mutable Audio::ManagerModel* m_pAudioManagerModel ; - mutable Audio::RingtoneDeviceModel* m_pRingtoneDeviceModel; - bool m_EnableRoomTone ; - -private Q_SLOTS: - void slotVolumeChanged(const QString& str, double volume); - -private: - Audio::Settings* q_ptr; -}; -} - -Audio::SettingsPrivate::SettingsPrivate(Audio::Settings* parent) : q_ptr(parent),m_EnableRoomTone(false), - m_pAlsaPluginModel (nullptr), m_pInputDeviceModel (nullptr), - m_pAudioManagerModel(nullptr), m_pRingtoneDeviceModel(nullptr), - m_pOutputDeviceModel(nullptr) -{ - -} - -///Constructor -Audio::Settings::Settings() : QObject(), d_ptr(new Audio::SettingsPrivate(this)) -{ - d_ptr->m_pRingtoneDeviceModel = new RingtoneDeviceModel (this); - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - connect(&configurationManager,SIGNAL(volumeChanged(QString,double)),d_ptr.data(),SLOT(slotVolumeChanged(QString,double))); -} - -///Destructor -Audio::Settings::~Settings() -{ - delete d_ptr->m_pAlsaPluginModel ; - delete d_ptr->m_pInputDeviceModel ; - delete d_ptr->m_pOutputDeviceModel ; - delete d_ptr->m_pAudioManagerModel ; - delete d_ptr->m_pRingtoneDeviceModel; -} - -///Singleton -Audio::Settings& Audio::Settings::instance() -{ - static auto instance = new Settings; - return *instance; -} - -///Return plugin model (alsa only for the time being) -Audio::AlsaPluginModel* Audio::Settings::alsaPluginModel() const -{ - if (!d_ptr->m_pAlsaPluginModel) - d_ptr->m_pAlsaPluginModel = new Audio::AlsaPluginModel(this); - return d_ptr->m_pAlsaPluginModel; -} - - -///Return the input device model -Audio::InputDeviceModel* Audio::Settings::inputDeviceModel() const -{ - if (!d_ptr->m_pInputDeviceModel) - d_ptr->m_pInputDeviceModel = new Audio::InputDeviceModel(this); - return d_ptr->m_pInputDeviceModel; -} - -///Return the output device model -Audio::OutputDeviceModel* Audio::Settings::outputDeviceModel() const -{ - if (!d_ptr->m_pOutputDeviceModel) - d_ptr->m_pOutputDeviceModel = new Audio::OutputDeviceModel(this); - return d_ptr->m_pOutputDeviceModel; -} - -///Return audio manager -Audio::ManagerModel* Audio::Settings::managerModel() const -{ - if (!d_ptr->m_pAudioManagerModel) - d_ptr->m_pAudioManagerModel = new Audio::ManagerModel(this); - return d_ptr->m_pAudioManagerModel; -} - -///Return the ringtone device model -Audio::RingtoneDeviceModel* Audio::Settings::ringtoneDeviceModel() const -{ - if (!d_ptr->m_pRingtoneDeviceModel) - d_ptr->m_pRingtoneDeviceModel = new Audio::RingtoneDeviceModel (this); - return d_ptr->m_pRingtoneDeviceModel; -} - -///Is the room tone (globally) enabled -bool Audio::Settings::isRoomToneEnabled() -{ - return d_ptr->m_EnableRoomTone; -} - -///Reload everything -void Audio::Settings::reload() -{ - alsaPluginModel ()->reload(); - inputDeviceModel ()->reload(); - outputDeviceModel ()->reload(); - ringtoneDeviceModel()->reload(); -} - -///Play room tone -Audio::Settings::ToneType Audio::Settings::playRoomTone() const -{ - CallManagerInterface& callManager = CallManager::instance(); - callManager.startTone(true,static_cast<int>(Audio::Settings::ToneType::WITHOUT_MESSAGE)); - //TODO support voicemail - return Audio::Settings::ToneType::WITHOUT_MESSAGE; -} - -///Stop room tone if it is playing -void Audio::Settings::stopRoomTone() const -{ - CallManagerInterface& callManager = CallManager::instance(); - callManager.startTone(false,0); -} - -///Set if the roomtone is (globally) enabled -void Audio::Settings::setEnableRoomTone(bool enable) -{ - d_ptr->m_EnableRoomTone = enable; -} - -///Enable noise suppress code, may make things worst -void Audio::Settings::setNoiseSuppressState(bool enabled) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setNoiseSuppressState(enabled); -} - -///Enable noise suppress code, may make things worst -bool Audio::Settings::isNoiseSuppressEnabled() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return configurationManager.getNoiseSuppressState(); -} - -///Mute playback -void Audio::Settings::mutePlayback(bool m) -{ - ConfigurationManager::instance().mutePlayback(m); - emit playbackMuted(m); -} - -///Mute capture -void Audio::Settings::muteCapture(bool m) -{ - ConfigurationManager::instance().muteCapture(m); - emit captureMuted(m); -} - -///is mute playback -bool Audio::Settings::isPlaybackMuted() const -{ - return ConfigurationManager::instance().isPlaybackMuted(); -} - -///is mute capture -bool Audio::Settings::isCaptureMuted() const -{ - return ConfigurationManager::instance().isCaptureMuted(); -} - -int Audio::Settings::playbackVolume() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return static_cast<int>(configurationManager.getVolume(DeviceKey::PLAYBACK)*100); -} - -int Audio::Settings::captureVolume() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return static_cast<int>(configurationManager.getVolume(DeviceKey::CAPTURE)*100); -} - -void Audio::Settings::setPlaybackVolume(int volume) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setVolume(DeviceKey::PLAYBACK,volume/100.0f); - emit playbackVolumeChanged(volume); -} - -void Audio::Settings::setCaptureVolume(int volume) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setVolume(DeviceKey::CAPTURE,volume/100.0f); - emit captureVolumeChanged(volume); -} - -void Audio::Settings::setDTMFMuted(bool muted) -{ - //TODO - ConfigurationManager::instance().muteDtmf(muted); - emit DTMFMutedChanged(muted); -} - -bool Audio::Settings::areDTMFMuted() const -{ - return ConfigurationManager::instance().isDtmfMuted(); -} - -///Called when the volume change for external reasons -void Audio::SettingsPrivate::slotVolumeChanged(const QString& str, double volume) -{ - if (str == Audio::Settings::DeviceKey::CAPTURE) - emit q_ptr->captureVolumeChanged(static_cast<int>(volume*100)); - else if (str == Audio::Settings::DeviceKey::PLAYBACK) - emit q_ptr->playbackVolumeChanged(static_cast<int>(volume*100)); - else - qDebug() << "Unknown audio device" << str; -} - -#include <settings.moc> diff --git a/src/audio/settings.h b/src/audio/settings.h deleted file mode 100644 index f5e92b1ee20120fe7e3d7cc4726edcbca0875e5f..0000000000000000000000000000000000000000 --- a/src/audio/settings.h +++ /dev/null @@ -1,109 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -//Ring -#include <typedefs.h> - - -namespace Audio { - -class AlsaPluginModel ; -class InputDeviceModel ; -class OutputDeviceModel ; -class ManagerModel ; -class RingtoneDeviceModel; - -class SettingsPrivate; - -/** - * This class group all ComboBox models used by audio settings dialogs - */ -class LIB_EXPORT Settings : public QObject { - Q_OBJECT -public: - - enum class DeviceIndex { - OUTPUT = 0, - INPUT = 1, - RINGTONE = 2, - }; - - virtual ~Settings(); - static Settings& instance(); - - //Getters - Audio::AlsaPluginModel* alsaPluginModel () const; - Audio::InputDeviceModel* inputDeviceModel () const; - Audio::OutputDeviceModel* outputDeviceModel () const; - Audio::ManagerModel* managerModel () const; - Audio::RingtoneDeviceModel* ringtoneDeviceModel() const; - bool isRoomToneEnabled (); - bool isNoiseSuppressEnabled () const; - bool isPlaybackMuted () const; - bool isCaptureMuted () const; - bool areDTMFMuted () const; - int playbackVolume () const; - int captureVolume () const; - - //Setters - void setEnableRoomTone ( bool enable ); - void setNoiseSuppressState( bool enabled ); - - //Room tone type - enum class ToneType { - WITHOUT_MESSAGE = 0, - WITH_MESSAGE = 1, - }; - - class DeviceKey { - public: - constexpr static const char* CAPTURE = "mic" ; - constexpr static const char* PLAYBACK = "speaker"; - }; - - //Mutator - ToneType playRoomTone() const; - void stopRoomTone() const; - -public Q_SLOTS: - void reload ( ); - void mutePlayback ( bool m ); - void muteCapture ( bool m ); - void setPlaybackVolume( int volume ); - void setCaptureVolume ( int volume ); - void setDTMFMuted ( bool muted ); - -Q_SIGNALS: - void captureMuted(bool); - void playbackMuted(bool); - void playbackVolumeChanged(int); - void captureVolumeChanged(int); - void DTMFMutedChanged(bool); - -private: - //Constructor - explicit Settings(); - QScopedPointer<SettingsPrivate> d_ptr; - Q_DECLARE_PRIVATE(Settings) -}; - -} - diff --git a/src/availableaccountmodel.cpp b/src/availableaccountmodel.cpp deleted file mode 100644 index c77e1cb87bb1e210cae0d764387c9a849871e928..0000000000000000000000000000000000000000 --- a/src/availableaccountmodel.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "availableaccountmodel.h" - -//Qt -#include <QtCore/QItemSelectionModel> -#include <QtCore/QCoreApplication> - -//DRing -#include <account_const.h> - -//Ring -#include "contactmethod.h" -#include "uri.h" - -class AvailableAccountModelPrivate final : public QObject -{ - Q_OBJECT -public: - AvailableAccountModelPrivate(AvailableAccountModel* parent); - - QItemSelectionModel* m_pSelectionModel; - static Account* m_spPriorAccount ; - - static void setPriorAccount ( const Account* account ); - static Account* firstRegisteredAccount( URI::SchemeType type = URI::SchemeType::NONE ); - - AvailableAccountModel* q_ptr; - -public Q_SLOTS: - void checkRemovedAccount(Account* a); - void checkStateChanges(Account* account, const Account::RegistrationState state); - void selectionChanged(const QModelIndex& idx, const QModelIndex& previous); -}; - -Account* AvailableAccountModelPrivate::m_spPriorAccount = nullptr; - -AvailableAccountModelPrivate::AvailableAccountModelPrivate(AvailableAccountModel* parent) :m_pSelectionModel(nullptr),q_ptr(parent) -{ - connect(&AccountModel::instance(), &AccountModel::accountRemoved , this, &AvailableAccountModelPrivate::checkRemovedAccount ); - connect(&AccountModel::instance(), &AccountModel::accountStateChanged, this, &AvailableAccountModelPrivate::checkStateChanges ); -} - -AvailableAccountModel::AvailableAccountModel(QObject* parent) : QSortFilterProxyModel(parent), -d_ptr(new AvailableAccountModelPrivate(this)) -{ - setSourceModel(&AccountModel::instance()); -} - -AvailableAccountModel::~AvailableAccountModel() -{ - delete d_ptr; -} - -AvailableAccountModel& AvailableAccountModel::instance() -{ - static auto instance = new AvailableAccountModel(QCoreApplication::instance()); - return *instance; -} - -//Do not show the checkbox -QVariant AvailableAccountModel::data(const QModelIndex& idx,int role ) const -{ - return (role == Qt::CheckStateRole) ? QVariant() : mapToSource(idx).data(role); -} - -///Disable the unavailable accounts -Qt::ItemFlags AvailableAccountModel::flags (const QModelIndex& idx) const -{ - const QModelIndex& src = mapToSource(idx); - if (qvariant_cast<Account::RegistrationState>(src.data(static_cast<int>(Account::Role::RegistrationState))) != Account::RegistrationState::READY) - return Qt::NoItemFlags; - return sourceModel()->flags(idx); -} - -//Do not display disabled account -bool AvailableAccountModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const -{ - return sourceModel()->index(source_row,0,source_parent).data(Qt::CheckStateRole) == Qt::Checked; -} - -///Return the current account -Account* AvailableAccountModel::currentDefaultAccount(ContactMethod* method) -{ - // if no CM is give, we use the user chosen account, since no other parameters are available - const auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex(); - if (!method && idx.isValid()) { - return idx.data(static_cast<int>(Account::Role::Object)).value<Account*>(); - } - - // Start by validating the scheme used by the ContactMethod - URI::SchemeType type = (!method) ? URI::SchemeType::NONE : method->uri().schemeType(); - - // If the scheme type could not be strictly determined, try using the protocol hint - if (type == URI::SchemeType::NONE && method) { - switch (method->protocolHint()) { - case URI::ProtocolHint::SIP_OTHER: - case URI::ProtocolHint::SIP_HOST: - case URI::ProtocolHint::IP: - type = URI::SchemeType::SIP; - break; - case URI::ProtocolHint::UNRECOGNIZED: - case URI::ProtocolHint::RING: - case URI::ProtocolHint::RING_USERNAME: - type = URI::SchemeType::RING; - break; - } - } - - return currentDefaultAccount(type); - -} //currentDefaultAccount - -/// Validation method to check if the account is in a good state and support the scheme provided -bool AvailableAccountModel::validAccountForScheme(Account* account, URI::SchemeType scheme) -{ - return (account - && account->registrationState() == Account::RegistrationState::READY - && account->isEnabled() - && (account->supportScheme(scheme))); -} - -Account* AvailableAccountModel::currentDefaultAccount(URI::SchemeType schemeType) -{ - // Always try to respect user choice - const auto idx = AvailableAccountModel::instance().selectionModel()->currentIndex(); - auto userChosenAccount = idx.data(static_cast<int>(Account::Role::Object)).value<Account*>(); - if (userChosenAccount && validAccountForScheme(userChosenAccount, schemeType)) { - return userChosenAccount; - } - - // If the current selected choice is not valid, try the previous account selected - auto priorAccount = AvailableAccountModelPrivate::m_spPriorAccount; - - //we prefer not to use Ip2Ip if possible - if (priorAccount && priorAccount->isIp2ip()) { - priorAccount = nullptr; - } - - if(validAccountForScheme(priorAccount, schemeType)) { - return priorAccount; - } else { - auto account = AvailableAccountModelPrivate::firstRegisteredAccount(schemeType); - - // If there is only RING account, it will still be nullptr. Given there is - // *only* RING accounts, then the user probably want a call using the - // Ring protocol. This will happen when using the name directory instead - // of the hash - if (!account) - account = AvailableAccountModelPrivate::firstRegisteredAccount( - URI::SchemeType::RING - ); - - AvailableAccountModelPrivate::setPriorAccount(account); - return account; - } -} - -///Set the previous account used -void AvailableAccountModelPrivate::setPriorAccount(const Account* account) -{ - const bool changed = (account && m_spPriorAccount != account) || (!account && m_spPriorAccount); - m_spPriorAccount = const_cast<Account*>(account); - if (changed) { - auto& self = AvailableAccountModel::instance(); - - Account* a = account ? const_cast<Account*>(account) : self.currentDefaultAccount(); - - emit self.currentDefaultAccountChanged(a); - - if (self.d_ptr->m_pSelectionModel) { - - const QModelIndex idx = self.mapFromSource(a->index()); - - if (idx.isValid()) - self.d_ptr->m_pSelectionModel->setCurrentIndex(self.mapFromSource(a->index()), QItemSelectionModel::ClearAndSelect); - else - self.d_ptr->m_pSelectionModel->clearSelection(); - } - } -} - -///Get the first registerred account (default account) -Account* AvailableAccountModelPrivate::firstRegisteredAccount(URI::SchemeType type) -{ - return AccountModel::instance().findAccountIf([&type](const Account& account) { - return account.registrationState() == Account::RegistrationState::READY - && account.isEnabled() - && account.supportScheme(type); - }); -} - -QItemSelectionModel* AvailableAccountModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<AvailableAccountModel*>(this)); - connect(d_ptr->m_pSelectionModel, &QItemSelectionModel::currentChanged,d_ptr,&AvailableAccountModelPrivate::selectionChanged); - Account* a = d_ptr->firstRegisteredAccount(); - if (a) - d_ptr->m_pSelectionModel->setCurrentIndex(mapFromSource(a->index()), QItemSelectionModel::ClearAndSelect); - } - return d_ptr->m_pSelectionModel; -} - -void AvailableAccountModelPrivate::selectionChanged(const QModelIndex& idx, const QModelIndex& previous) -{ - Q_UNUSED(previous) - Account* a = qvariant_cast<Account*>(idx.data(static_cast<int>(Account::Role::Object))); - - setPriorAccount(a); -} - -void AvailableAccountModelPrivate::checkRemovedAccount(Account* a) -{ - if (a == m_spPriorAccount) { - Account* a2 = firstRegisteredAccount(); - qDebug() << "The current default account has been removed, now defaulting to" << a2; - setPriorAccount(a2); - } -} - -void AvailableAccountModelPrivate::checkStateChanges(Account* account, const Account::RegistrationState state) -{ - // change PriorAccount if current PriorAccount became unavailable - if(m_spPriorAccount != account || state == Account::RegistrationState::READY || - state == Account::RegistrationState::TRYING) - return; - Account* a = firstRegisteredAccount(); - setPriorAccount(a); -} - -#include <availableaccountmodel.moc> diff --git a/src/avmodel.cpp b/src/avmodel.cpp index 5a6cd923c69de04920836c4fbf5b71c2fdf16c5f..d751c4d0d35d59b6a8e3c64edc902bdf55395b95 100644 --- a/src/avmodel.cpp +++ b/src/avmodel.cpp @@ -44,9 +44,6 @@ #include "dbus/videomanager.h" #include "database.h" -// TODO(sblin) remove this as soon as all clients use this class -#include <private/videorenderermanager.h> - namespace lrc { @@ -82,9 +79,6 @@ public: */ std::string getDevice(int type) const; - // This method is temporary and has to be removed when videorenderermanager will be deleted - void init(); - public Q_SLOTS: /** * Listen from CallbacksHandler when a renderer starts @@ -440,14 +434,25 @@ AVModel::startLocalRecorder(const bool& audioOnly) const return finalPath.toStdString(); } +std::string +AVModel::getRecordPath() const +{ + QString path = ConfigurationManager::instance().getRecordPath(); + return path.toStdString(); +} + +void +AVModel::setRecordPath(const std::string& path) const +{ + ConfigurationManager::instance().setRecordPath(QString::fromStdString(path).toUtf8()); +} + void AVModel::useAVFrame(bool useAVFrame) { pimpl_->useAVFrame_ = useAVFrame; for (auto it = pimpl_->renderers_.cbegin(); it != pimpl_->renderers_.cend(); ++it) { it->second->useAVFrame(pimpl_->useAVFrame_); } - //TODO remove when switch to new av model - VideoRendererManager::instance().useAVFrame(useAVFrame); } void @@ -570,23 +575,11 @@ AVModel::getCurrentRenderedDevice(const std::string& call_id) const return result; } -void -AVModel::deactivateOldVideoModels() -{ - VideoRendererManager::instance().deactivate(); - pimpl_->init(); -} - AVModelPimpl::AVModelPimpl(AVModel& linked, const CallbacksHandler& callbacksHandler) : linked_(linked) , callbacksHandler(callbacksHandler) { std::srand(std::time(nullptr)); -} - -void -AVModelPimpl::init() -{ // add preview renderer renderers_.insert(std::make_pair(video::PREVIEW_RENDERER_ID, std::make_unique<video::Renderer>(video::PREVIEW_RENDERER_ID, @@ -631,7 +624,12 @@ AVModelPimpl::init() std::string AVModelPimpl::getRecordingPath() const { +#if defined(_WIN32) || defined(__APPLE__) + const QDir dir = QString::fromStdString(linked_.getRecordPath()) + "/" + recorderSavesSubdir.c_str(); +#else const QDir dir = lrc::Database::getPath() + "/" + recorderSavesSubdir.c_str(); +#endif + dir.mkpath("."); std::chrono::time_point<std::chrono::system_clock> time_now = std::chrono::system_clock::now(); diff --git a/src/behaviorcontroller.cpp b/src/behaviorcontroller.cpp index 27e6a7b67bff2b2460bf38a6da7911bff7b4c4b6..689f4f7623a4daa6fabe23b2846392c57c50038f 100644 --- a/src/behaviorcontroller.cpp +++ b/src/behaviorcontroller.cpp @@ -39,4 +39,3 @@ BehaviorController::~BehaviorController() } // namespace lrc #include "api/moc_behaviorcontroller.cpp" -#include "behaviorcontroller.moc" diff --git a/src/call.cpp b/src/call.cpp deleted file mode 100644 index 522d3ec2adafd9a2e1945af0c75eadab63d8a6e8..0000000000000000000000000000000000000000 --- a/src/call.cpp +++ /dev/null @@ -1,2235 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -//Parent -#include "call.h" - -//Std include -#include <fstream> -#include <memory> -#include <string> -#include <time.h> - -//Qt -#include <QtCore/QFile> -#include <QtCore/QTimer> -#include <QtCore/QDateTime> -#include <QtCore/QStandardPaths> - -//DRing -#include <account_const.h> -#include <security_const.h> -#include <call_const.h> - -//Ring library -#include "dbus/callmanager.h" -#include "dbus/configurationmanager.h" - -#include "collectioninterface.h" -#include "person.h" -#include "uri.h" -#include <mime.h> -#include "account.h" -#include "accountmodel.h" -#include "private/videorenderermanager.h" -#include "certificate.h" -#include "numbercategory.h" -#include "certificatemodel.h" -#include "phonedirectorymodel.h" -#include "contactmethod.h" -#include "video/renderer.h" -#include "video/sourcemodel.h" -#include "audio/settings.h" -#include "personmodel.h" -#include "private/contactmethod_p.h" - -#include "database.h" -#include "authority/databasehelper.h" - -#include "media/audio.h" -#include "media/video.h" -#include "media/text.h" -#include "media/file.h" - -#include "securityevaluationmodel.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" - -//Track where state changes are performed on finished (over, error, failed) calls -//while not really problematic, it is technically wrong -#define Q_ASSERT_IS_IN_PROGRESS Q_ASSERT(m_CurrentState != Call::State::OVER); -#define FORCE_ERROR_STATE() {qDebug() << "Fatal error on " << this << __FILE__ << __LINE__;\ - d_ptr->changeCurrentState(Call::State::ERROR);} - -#define FORCE_ERROR_STATE_P() {qDebug() << "Fatal error on " << this << __FILE__ << __LINE__;\ - changeCurrentState(Call::State::ERROR);} - -#include "private/call_p.h" - -const TypedStateMachine< TypedStateMachine< Call::State , Call::Action> , Call::State> CallPrivate::actionPerformedStateMap = -{{ -// ACCEPT REFUSE TRANSFER HOLD RECORD /**/ -/*NEW */ {{Call::State::DIALING , Call::State::ABORTED , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*INCOMING */ {{Call::State::INCOMING , Call::State::INCOMING , Call::State::ERROR , Call::State::INCOMING , Call::State::INCOMING }},/**/ -/*RINGING */ {{Call::State::ERROR , Call::State::RINGING , Call::State::ERROR , Call::State::ERROR , Call::State::RINGING }},/**/ -/*CURRENT */ {{Call::State::ERROR , Call::State::CURRENT , Call::State::TRANSFERRED , Call::State::CURRENT , Call::State::CURRENT }},/**/ -/*DIALING */ {{Call::State::INITIALIZATION, Call::State::OVER , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*HOLD */ {{Call::State::ERROR , Call::State::HOLD , Call::State::TRANSF_HOLD , Call::State::HOLD , Call::State::HOLD }},/**/ -/*FAILURE */ {{Call::State::ERROR , Call::State::OVER , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*BUSY */ {{Call::State::ERROR , Call::State::BUSY , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*TRANSFER */ {{Call::State::TRANSFERRED , Call::State::TRANSFERRED , Call::State::CURRENT , Call::State::TRANSFERRED , Call::State::TRANSFERRED }},/**/ -/*TRANSF_HOLD */ {{Call::State::TRANSF_HOLD , Call::State::TRANSF_HOLD , Call::State::HOLD , Call::State::TRANSF_HOLD , Call::State::TRANSF_HOLD }},/**/ -/*OVER */ {{Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*ERROR */ {{Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*CONF */ {{Call::State::ERROR , Call::State::CURRENT , Call::State::TRANSFERRED , Call::State::CURRENT , Call::State::CURRENT }},/**/ -/*CONF_HOLD */ {{Call::State::ERROR , Call::State::HOLD , Call::State::TRANSF_HOLD , Call::State::HOLD , Call::State::HOLD }},/**/ -/*INIT */ {{Call::State::INITIALIZATION, Call::State::OVER , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*ABORTED */ {{Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*CONNECTED */ {{Call::State::ERROR , Call::State::OVER , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -}};// */ - -#define CP &CallPrivate -const TypedStateMachine< TypedStateMachine< function , Call::Action > , Call::State > CallPrivate::actionPerformedFunctionMap = -{{ -// ACCEPT REFUSE TRANSFER HOLD AUDIO_RECORD VIDEO_RECORD TEXT_RECORD /**/ -/*NEW */ {{CP::nothing , CP::abort , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*INCOMING */ {{CP::accept , CP::refuse , CP::acceptTransf , CP::acceptHold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*RINGING */ {{CP::nothing , CP::hangUp , CP::nothing , CP::nothing , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*CURRENT */ {{CP::nothing , CP::hangUp , CP::nothing , CP::hold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*DIALING */ {{CP::call , CP::abort , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*HOLD */ {{CP::nothing , CP::hangUp , CP::nothing , CP::unhold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*FAILURE */ {{CP::nothing , CP::remove , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*BUSY */ {{CP::nothing , CP::hangUp , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*TRANSFERT */ {{CP::transfer , CP::hangUp , CP::transfer , CP::hold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*TRANSFERT_HOLD */ {{CP::transfer , CP::hangUp , CP::transfer , CP::unhold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*OVER */ {{CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*ERROR */ {{CP::nothing , CP::remove , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*CONF */ {{CP::nothing , CP::hangUp , CP::nothing , CP::hold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*CONF_HOLD */ {{CP::nothing , CP::hangUp , CP::nothing , CP::unhold , CP::toggleAudioRecord , CP::toggleVideoRecord , CP::nothing }},/**/ -/*INITIALIZATION */ {{CP::call , CP::cancel , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*ABORTED */ {{CP::nothing , CP::cancel , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -/*CONNECTED */ {{CP::nothing , CP::cancel , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing }},/**/ -}};// */ - -const TypedStateMachine< TypedStateMachine< Call::State , CallPrivate::DaemonState> , Call::State> CallPrivate::stateChangedStateMap = -{{ -// RINGING CONNECTING CURRENT BUSY HOLD HUNGUP FAILURE OVER INACTIVE /**/ -/*NEW */ {{Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::INITIALIZATION}},/**/ -/*INCOMING */ {{Call::State::INCOMING , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::INCOMING }},/**/ -/*RINGING */ {{Call::State::RINGING , Call::State::CONNECTED , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::RINGING }},/**/ -/*CURRENT */ {{Call::State::CURRENT , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*DIALING */ {{Call::State::RINGING , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*HOLD */ {{Call::State::HOLD , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*FAILURE */ {{Call::State::FAILURE , Call::State::ERROR , Call::State::FAILURE , Call::State::BUSY , Call::State::FAILURE , Call::State::OVER , Call::State::FAILURE , Call::State::FAILURE , Call::State::ERROR }},/**/ -/*BUSY */ {{Call::State::BUSY , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::BUSY , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*TRANSFER */ {{Call::State::TRANSFERRED , Call::State::ERROR , Call::State::TRANSFERRED, Call::State::BUSY , Call::State::TRANSF_HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*TRANSF_HOLD */ {{Call::State::TRANSF_HOLD , Call::State::ERROR , Call::State::TRANSFERRED, Call::State::BUSY , Call::State::TRANSF_HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*OVER */ {{Call::State::OVER , Call::State::OVER , Call::State::OVER , Call::State::OVER , Call::State::OVER , Call::State::OVER , Call::State::OVER , Call::State::OVER , Call::State::ERROR }},/**/ -/*ERROR */ {{Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*CONF */ {{Call::State::CURRENT , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*CONF_HOLD */ {{Call::State::HOLD , Call::State::ERROR , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::ERROR }},/**/ -/*INIT */ {{Call::State::RINGING , Call::State::INITIALIZATION, Call::State::CURRENT, Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::INITIALIZATION}},/**/ -/*ABORTED */ {{Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR , Call::State::ERROR }},/**/ -/*CONNECTED */ {{Call::State::RINGING , Call::State::CONNECTED , Call::State::CURRENT , Call::State::BUSY , Call::State::HOLD , Call::State::OVER , Call::State::FAILURE , Call::State::OVER , Call::State::CONNECTED }},/**/ -}};// */ - -const TypedStateMachine< TypedStateMachine< function , CallPrivate::DaemonState > , Call::State > CallPrivate::stateChangedFunctionMap = -{{ -// RINGING CONNECTING CURRENT BUSY HOLD HUNGUP FAILURE OVER INACTIVE /**/ -/*NEW */ {{CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::nothing}}, /**/ -/*INCOMING */ {{CP::nothing , CP::nothing , CP::start , CP::startWeird , CP::startWeird , CP::startStop , CP::failure , CP::nothing , CP::nothing}}, /**/ -/*RINGING */ {{CP::nothing , CP::nothing , CP::start , CP::failure , CP::start , CP::startStop , CP::failure , CP::nothing , CP::nothing}}, /**/ -/*CURRENT */ {{CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::nothing , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*DIALING */ {{CP::nothing , CP::nothing , CP::warning , CP::warning , CP::warning , CP::stop , CP::warning , CP::stop , CP::nothing}}, /**/ -/*HOLD */ {{CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::nothing , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*FAILURE */ {{CP::nothing , CP::nothing , CP::warning , CP::warning , CP::warning , CP::stop , CP::nothing , CP::nothing , CP::nothing}}, /**/ -/*BUSY */ {{CP::nothing , CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*TRANSFERT */ {{CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::nothing , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*TRANSFERT_HOLD */ {{CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::nothing , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*OVER */ {{CP::nothing , CP::nothing , CP::warning , CP::warning , CP::warning , CP::stop , CP::warning , CP::nothing , CP::nothing}}, /**/ -/*ERROR */ {{CP::error , CP::error , CP::error , CP::error , CP::error , CP::stop , CP::error , CP::error , CP::nothing}}, /**/ -/*CONF */ {{CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::nothing , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*CONF_HOLD */ {{CP::nothing , CP::nothing , CP::nothing , CP::warning , CP::nothing , CP::stop , CP::nothing , CP::stop , CP::nothing}}, /**/ -/*INIT */ {{CP::nothing , CP::nothing , CP::warning , CP::warning , CP::warning , CP::stop , CP::warning , CP::stop , CP::nothing}}, /**/ -/*ABORTED */ {{CP::error , CP::error , CP::error , CP::error , CP::error , CP::error , CP::error , CP::error , CP::nothing}}, /**/ -/*CONNECTED */ {{CP::nothing , CP::nothing , CP::warning , CP::warning , CP::warning , CP::stop , CP::warning , CP::stop , CP::nothing}}, /**/ -}};// */ - -//There is no point to have a 2D matrix, only one transition per state is possible -const Matrix1D<Call::LifeCycleState,function> CallPrivate::m_mLifeCycleStateChanges = {{ -/* CREATION */ CP::nothing , -/* INITIALIZATION */ CP::nothing , -/* PROGRESS */ CP::initMedia , -/* FINISHED */ CP::terminateMedia, -}}; -#undef CP - -const TypedStateMachine< Call::LifeCycleState , Call::State > CallPrivate::metaStateMap = -{{ -/* * Life cycle meta-state **/ -/*NEW */ Call::LifeCycleState::CREATION ,/**/ -/*INCOMING */ Call::LifeCycleState::INITIALIZATION ,/**/ -/*RINGING */ Call::LifeCycleState::INITIALIZATION ,/**/ -/*CURRENT */ Call::LifeCycleState::PROGRESS ,/**/ -/*DIALING */ Call::LifeCycleState::CREATION ,/**/ -/*HOLD */ Call::LifeCycleState::PROGRESS ,/**/ -/*FAILURE */ Call::LifeCycleState::FINISHED ,/**/ -/*BUSY */ Call::LifeCycleState::FINISHED ,/**/ -/*TRANSFERT */ Call::LifeCycleState::PROGRESS ,/**/ -/*TRANSFERT_HOLD */ Call::LifeCycleState::PROGRESS ,/**/ -/*OVER */ Call::LifeCycleState::FINISHED ,/**/ -/*ERROR */ Call::LifeCycleState::FINISHED ,/**/ -/*CONF */ Call::LifeCycleState::PROGRESS ,/**/ -/*CONF_HOLD */ Call::LifeCycleState::PROGRESS ,/**/ -/*INIT */ Call::LifeCycleState::INITIALIZATION ,/**/ -/*ABORTED */ Call::LifeCycleState::FINISHED ,/**/ -/*CONNECTED */ Call::LifeCycleState::INITIALIZATION ,/**/ -}};/* **/ - -const TypedStateMachine< TypedStateMachine< bool , Call::LifeCycleState > , Call::State > CallPrivate::metaStateTransitionValidationMap = -{{ -/* * CREATION INITIALIZATION PROGRESS FINISHED **/ -/*NEW */ {{ true , true , false , false }},/**/ -/*INCOMING */ {{ false , true , false , false }},/**/ -/*RINGING */ {{ true , true , false , false }},/**/ -/*CURRENT */ {{ false , true , true , false }},/**/ -/*DIALING */ {{ true , true , false , false }},/**/ -/*HOLD */ {{ false , true , true , false }},/**/ -/*FAILURE */ {{ false , true , true , true }},/**/ -/*BUSY */ {{ false , true , false , true }},/**/ -/*TRANSFERT */ {{ false , false , true , false }},/**/ -/*TRANSFERT_HOLD */ {{ false , false , true , false }},/**/ -/*OVER */ {{ false , true , true , true }},/**/ -/*ERROR */ {{ true , true , true , true }},/**/ -/*CONF */ {{ false , true , false , false }},/**/ -/*CONF_HOLD */ {{ false , true , false , false }},/**/ -/*INIT */ {{ true , true , false , false }},/**/ -/*ABORTED */ {{ true , true , false , true }},/**/ -/*INITIALIZATION */ {{ true , true , false , false }},/**/ -}};/* **/ -/*^^ A call _can_ be created on hold (conference) and as over (peer hang up before pickup) - the progress->failure one is an implementation bug*/ - -QDebug LIB_EXPORT operator<<(QDebug dbg, const CallPrivate::DaemonState& c ); - -QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::State& c) -{ - dbg.nospace() << Call::toHumanStateName(c); - return dbg.space(); -} - -QDebug LIB_EXPORT operator<<(QDebug dbg, const CallPrivate::DaemonState& c) -{ - dbg.nospace() << static_cast<int>(c); - return dbg.space(); -} - -QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::Action& c) -{ - switch (c) { - case Call::Action::ACCEPT: - dbg.nospace() << "ACCEPT"; - break; - case Call::Action::REFUSE: - dbg.nospace() << "REFUSE"; - break; - case Call::Action::TRANSFER: - dbg.nospace() << "TRANSFER"; - break; - case Call::Action::HOLD: - dbg.nospace() << "HOLD"; - break; - case Call::Action::RECORD_AUDIO: - dbg.nospace() << "RECORD_AUDIO"; - break; - case Call::Action::RECORD_VIDEO: - dbg.nospace() << "RECORD_VIDEO"; - break; - case Call::Action::RECORD_TEXT: - dbg.nospace() << "RECORD_TEXT"; - break; - case Call::Action::COUNT__: - dbg.nospace() << "COUNT"; - break; - }; - dbg.space(); - dbg.nospace() << '(' << static_cast<int>(c) << ')'; - return dbg.space(); -} - -CallPrivate::CallPrivate(Call* parent) : QObject(parent),q_ptr(parent), -m_pStopTimeStamp(0),m_pTimer(nullptr),m_Account(nullptr), -m_PeerName(),m_pPeerContactMethod(nullptr), -m_pStartTimeStamp(0), -m_pDialNumber(new TemporaryContactMethod()), -m_History(false),m_Missed(false),m_Direction(Call::Direction::OUTGOING),m_Type(Call::Type::CALL), -m_CurrentState(Call::State::ERROR),m_pCertificate(nullptr),m_mMedias({{ - /* IN OUT */ - /* AUDIO */ {{ new QList<media::Media*>() /*Created lifecycle == progress*/, new QList<media::Media*>() /*Created lifecycle == progress*/}}, - /* VIDEO */ {{ new QList<media::Media*>() /*On demand */, new QList<media::Media*>() /*On demand */}}, - /* TEXT */ {{ new QList<media::Media*>() /*On demand */, new QList<media::Media*>() /*On demand */}}, - /* FILE */ {{ new QList<media::Media*>() /*Not implemented */, new QList<media::Media*>() /*Not implemented */}}, -}}), m_mRecordings({{ - /* IN OUT */ - /* AUDIO */ {{ new QList<media::Recording*>(), new QList<media::Recording*>()}}, - /* VIDEO */ {{ new QList<media::Recording*>(), new QList<media::Recording*>()}}, - /* TEXT */ {{ new QList<media::Recording*>(), new QList<media::Recording*>()}}, - /* FILE */ {{ new QList<media::Recording*>(), new QList<media::Recording*>()}}, -}}), m_mIsRecording({{ - /* IN OUT */ - /* AUDIO */ {{ false, false }}, - /* VIDEO */ {{ false, false }}, - /* TEXT */ {{ false, false }}, - /* FILE */ {{ false, false }}, -}}), m_pTransferNumber(nullptr) -{ -} - -///Constructor -Call::Call(Call::State startState, const QString& peerName, ContactMethod* number, Account* account) - : ItemBase() - , d_ptr(new CallPrivate(this)) -{ - d_ptr->m_CurrentState = startState; - d_ptr->m_Type = Call::Type::CALL; - d_ptr->m_Account = account; - d_ptr->m_PeerName = peerName; - d_ptr->m_pPeerContactMethod = number; - - emit changed(); -} - -///Constructor -Call::Call(const QString& confId, const QString& account) - : ItemBase() - , d_ptr(new CallPrivate(this)) -{ - d_ptr->m_CurrentState = Call::State::CONFERENCE; - d_ptr->m_Account = AccountModel::instance().getById(account.toLatin1()); - d_ptr->m_Type = (!confId.isEmpty())?Call::Type::CONFERENCE:Call::Type::CALL; - d_ptr->m_DringId = confId; - - setObjectName("Conf:"+confId); - - if (type() == Call::Type::CONFERENCE) { - d_ptr->setStartTimeStamp(); - d_ptr->initTimer(); - CallManagerInterface& callManager = CallManager::instance(); - MapStringString details = callManager.getConferenceDetails(dringId()) ; - d_ptr->m_CurrentState = d_ptr->confStatetoCallState(details[CallPrivate::ConfDetailsMapFields::CONF_STATE]); - emit stateChanged(state(),Call::State::NEW); - } -} - -///Destructor -Call::~Call() -{ - if (d_ptr->m_pTimer) - delete d_ptr->m_pTimer; - - this->disconnect(); - - d_ptr->terminateMedia(); - - if (d_ptr->m_pDateOnly) - delete d_ptr->m_pDateOnly; - - if (d_ptr->m_pDateTime) - delete d_ptr->m_pDateTime; - - delete d_ptr; -} - -CallPrivate::~CallPrivate() -{ - for ( const media::Media::Type t : EnumIterator<media::Media::Type>()) { - if (m_mMedias[t][media::Media::Direction::IN ]) - delete m_mMedias[t][media::Media::Direction::IN ]; - if (m_mMedias[t][media::Media::Direction::OUT ]) - delete m_mMedias[t][media::Media::Direction::OUT ]; - - if (m_mRecordings[t][media::Media::Direction::IN ]) - delete m_mRecordings[t][media::Media::Direction::IN ]; - if (m_mRecordings[t][media::Media::Direction::OUT ]) - delete m_mRecordings[t][media::Media::Direction::OUT ]; - } -} - -/***************************************************************************** - * * - * Call builder * - * * - ****************************************************************************/ - -void CallPrivate::deleteCall(Call* call) -{ - delete call; -} - -void CallPrivate::updateOutgoingMedia(const MapStringString& details) -{ - auto list = q_ptr->media(media::Media::Type::VIDEO, media::Media::Direction::OUT); - QString video_source = details[ DRing::Call::Details::VIDEO_SOURCE]; - - if (video_source.length() <= 0 && list.isEmpty()) { - // Means there is no video, and there never was. Nothing to do. - return; - } - - if (list.isEmpty()) { - // Update data - static const media::Media::Direction direction = media::Media::Direction::OUT; - mediaFactory<media::Video>(direction); - } - - list = q_ptr->media(media::Media::Type::VIDEO, media::Media::Direction::OUT); - media::Video* media_video = static_cast<media::Video*>(list[0]); - media_video->sourceModel()->setUsedIndex(video_source); - return; -} - -MapStringString CallPrivate::getCallDetailsCommon(const QString& callId) -{ - CallManagerInterface& callManager = CallManager::instance(); - - MapStringString details = callManager.getCallDetails(callId); - - const QString account = details[ DRing::Call::Details::ACCOUNTID ]; - - if (account.isEmpty()) - return details; - - Account* acc = AccountModel::instance().getById(account.toLatin1()); - - //Only keep the useful part of the URI - if (acc && acc->protocol() == Account::Protocol::RING) - details[DRing::Call::Details::PEER_NUMBER] = URI(details[DRing::Call::Details::PEER_NUMBER]).format( - URI::Section::SCHEME | - URI::Section::USER_INFO - ); - else - details[DRing::Call::Details::PEER_NUMBER] = URI(details[DRing::Call::Details::PEER_NUMBER]).format( - URI::Section::SCHEME | - URI::Section::USER_INFO | - URI::Section::HOSTNAME - ); - - return details; -} - -///Build a call from a dbus event -Call* CallPrivate::buildCall(const QString& callId, Call::Direction callDirection, Call::State startState) -{ - const auto& details = getCallDetailsCommon(callId); - - const auto& peerNumber = details[ DRing::Call::Details::PEER_NUMBER ]; - const auto& peerName = details[ DRing::Call::Details::DISPLAY_NAME]; - const auto& account = details[ DRing::Call::Details::ACCOUNTID ]; - - //It may be possible that the call has already been invalidated - if (account.isEmpty()) { - qWarning() << "Building call" << callId << "failed, it may already have been destroyed by the daemon"; - return nullptr; - } - - const auto& acc = AccountModel::instance().getById(account.toLatin1()); - const auto& nb = PhoneDirectoryModel::instance().getNumber(peerNumber, acc); - - auto call = std::unique_ptr<Call, decltype(deleteCall)&>( new Call(startState, peerName, nb, acc), - deleteCall ); - call->d_ptr->updateOutgoingMedia(details); - - call->d_ptr->m_DringId = callId; - call->d_ptr->m_Direction = callDirection; - call->d_ptr->m_pParentCall = nullptr; - - //Set the recording state - if (CallManager::instance().getIsRecording(callId)) { - call->d_ptr->m_mIsRecording[ media::Media::Type::AUDIO ].setAt( media::Media::Direction::IN , true); - call->d_ptr->m_mIsRecording[ media::Media::Type::AUDIO ].setAt( media::Media::Direction::OUT , true); - call->d_ptr->m_mIsRecording[ media::Media::Type::VIDEO ].setAt( media::Media::Direction::IN , true); - call->d_ptr->m_mIsRecording[ media::Media::Type::VIDEO ].setAt( media::Media::Direction::OUT , true); - } - - if (!details[ DRing::Call::Details::TIMESTAMP_START ].isEmpty()) - call->d_ptr->setStartTimeStamp(details[ DRing::Call::Details::TIMESTAMP_START ].toInt()); - else - call->d_ptr->setStartTimeStamp(); - - call->d_ptr->initTimer(); - - if (call->peerContactMethod()) - call->peerContactMethod()->addCall(call.get()); - - //Load the certificate if it's now available - if (!call->certificate() && !details[DRing::TlsTransport::TLS_PEER_CERT].isEmpty()) { - auto cert = CertificateModel::instance().getCertificateFromId(details[DRing::TlsTransport::TLS_PEER_CERT], call->account()); - call->d_ptr->m_pCertificate = cert; - nb->d_ptr->setCertificate(cert); - } - - return call.release(); -} //buildCall - -///Build a call from its ID -Call* CallPrivate::buildExistingCall(const QString& callId) -{ - const auto& details = getCallDetailsCommon(callId); - const auto daemon_state = details[DRing::Call::Details::CALL_STATE]; - const auto daemon_type = details[DRing::Call::Details::CALL_TYPE]; - const auto direction = daemon_type == CallPrivate::CallDirection::OUTGOING ? Call::Direction::OUTGOING : Call::Direction::INCOMING; - return buildCall(callId, direction, startStateFromDaemonCallState(daemon_state, daemon_type)); -} - -///Build a call from a dbus event -Call* CallPrivate::buildIncomingCall(const QString& callId) -{ - return buildCall(callId, Call::Direction::INCOMING, Call::State::INCOMING); -} //buildIncomingCall - -///Build a call from a dialing call (a call that is about to exist, not existing on daemon yet) -Call* CallPrivate::buildDialingCall(const QString& peerName, Account* account, Call* parent) -{ - auto call = std::unique_ptr<Call, decltype(deleteCall)&>( new Call(Call::State::NEW, - peerName, nullptr, account), - deleteCall ); - call->d_ptr->m_Direction = Call::Direction::OUTGOING; - call->d_ptr->m_pParentCall = parent; - if (Audio::Settings::instance().isRoomToneEnabled()) { - Audio::Settings::instance().playRoomTone(); - } - - return call.release(); -} - -/***************************************************************************** - * * - * History * - * * - ****************************************************************************/ - -///Build a call that is already over -Call* Call::buildHistoryCall(const QMap<QString,QString>& hc) -{ - const QString& callId = hc[ Call::HistoryMapFields::CALLID ] ; - const QString& name = hc[ Call::HistoryMapFields::DISPLAY_NAME ] ; - const QString& number = hc[ Call::HistoryMapFields::PEER_NUMBER ] ; - //const QString& type = hc[ Call::HistoryMapFields::STATE ] ; - const QString& direction = hc[ Call::HistoryMapFields::DIRECTION ] ; - const QString& rec_path = hc[ Call::HistoryMapFields::RECORDING_PATH ] ; - const QString& cert_path = hc[ Call::HistoryMapFields::CERT_PATH ] ; - const bool missed = hc[ Call::HistoryMapFields::MISSED ] == "1" ; - time_t startTimeStamp = hc[ Call::HistoryMapFields::TIMESTAMP_START ].toUInt() ; - time_t stopTimeStamp = hc[ Call::HistoryMapFields::TIMESTAMP_STOP ].toUInt() ; - QByteArray accId = hc[ Call::HistoryMapFields::ACCOUNT_ID ].toLatin1(); - - if (accId.isEmpty()) { - qWarning() << "A history call has an invalid account identifier"; - - // DISABLED: removed IP2IP support, tuleap: #448 - // accId = DRing::Account::ProtocolNames::IP2IP; - } - - // fix invalid time values - if (startTimeStamp <= 0) { - startTimeStamp = (QDateTime::currentDateTime().currentMSecsSinceEpoch()) / Q_INT64_C(1000); - stopTimeStamp = startTimeStamp; - } else if (stopTimeStamp <= 0) { - stopTimeStamp = startTimeStamp; - } - - //Try to assiciate a contact now, the real contact object is probably not - //loaded yet, but we can get a placeholder for now - const QString& contactUid = hc[ Call::HistoryMapFields::CONTACT_UID ]; - Person* ct = nullptr; - if (!contactUid.isEmpty()) - ct = PersonModel::instance().getPlaceHolder(contactUid.toLatin1()); - - Account* acc = AccountModel::instance().getById(accId); - ContactMethod* nb = PhoneDirectoryModel::instance().getNumber(number,ct,acc); - - Call* call = new Call(Call::State::OVER, (name == "empty")?QString():name, nb, acc ); - call->d_ptr->m_DringId = callId; - - call->d_ptr->m_pStopTimeStamp = stopTimeStamp ; - call->d_ptr->setStartTimeStamp(startTimeStamp); - call->d_ptr->setRecordingPath (rec_path); - call->d_ptr->m_History = true; - call->d_ptr->m_Account = AccountModel::instance().getById(accId); - - if (missed) { - call->d_ptr->m_Missed = true; - } - if (!direction.isEmpty()) { - if (direction == Call::HistoryStateName::INCOMING) { - call->d_ptr->m_Direction = Call::Direction::INCOMING ; - } - else if (direction == Call::HistoryStateName::OUTGOING) { - call->d_ptr->m_Direction = Call::Direction::OUTGOING ; - } - } - else //Getting there is a bug. Pick one, even if it is the wrong one - call->d_ptr->m_Direction = Call::Direction::OUTGOING ; - - call->setObjectName("History:"+call->d_ptr->m_DringId); - - if (call->peerContactMethod()) { - call->peerContactMethod()->addCall(call); - - //Reload the glow and number colors - connect(call->peerContactMethod(),SIGNAL(presentChanged(bool)),call->d_ptr,SLOT(updated())); - - //Change the display name and picture - connect(call->peerContactMethod(),SIGNAL(rebased(ContactMethod*)),call->d_ptr,SLOT(updated())); - } - - //Check the certificate - if (!cert_path.isEmpty()) { - call->d_ptr->m_pCertificate = CertificateModel::instance().getCertificateFromPath(cert_path,acc); - } - - //Allow the certificate - if (acc && acc->allowIncomingFromHistory() && acc->protocol() == Account::Protocol::RING) { - auto certid = nb->uri().userinfo(); // certid must only contain the hash, no scheme - acc->allowCertificate(CertificateModel::instance().getCertificateFromId(certid, acc)); - } - - return call; -} - -/// aCall << Call::Action::HOLD -Call* Call::operator<<( Call::Action& c) -{ - performAction(c); - return this; -} - -Call* operator<<(Call* c, Call::Action action) -{ - return (!c) ? nullptr : (*c) << action; -} - -///Get the start sate from the daemon state -Call::State CallPrivate::startStateFromDaemonCallState(const QString& daemonCallState, const QString& daemonCallType) -{ - if(daemonCallState == DRing::Call::StateEvent::CURRENT ) - return Call::State::CURRENT ; - else if(daemonCallState == DRing::Call::StateEvent::HOLD ) - return Call::State::HOLD ; - else if(daemonCallState == DRing::Call::StateEvent::BUSY ) - return Call::State::BUSY ; - else if(daemonCallState == DRing::Call::StateEvent::INCOMING ) - return Call::State::INCOMING ; - else if(daemonCallState == DRing::Call::StateEvent::CONNECTING && daemonCallType == CallPrivate::CallDirection::INCOMING ) - return Call::State::INCOMING ; - else if(daemonCallState == DRing::Call::StateEvent::CONNECTING && daemonCallType == CallPrivate::CallDirection::OUTGOING ) - return Call::State::RINGING ; - else if(daemonCallState == DRing::Call::StateEvent::RINGING ) - return Call::State::RINGING ; - else if(daemonCallState == DRing::Call::StateEvent::INACTIVE ) - return Call::State::INITIALIZATION; - else - return Call::State::FAILURE ; -} //startStateFromDaemonCallState - -/***************************************************************************** - * * - * Getters * - * * - ****************************************************************************/ - -///Transfer state from internal to daemon internal syntaz -CallPrivate::DaemonState CallPrivate::toDaemonCallState(const QString& stateName) -{ - //TODO use a hash for this as it grow larger - if(stateName == CallPrivate::StateChange::HUNG_UP ) - return CallPrivate::DaemonState::HUNG_UP ; - if(stateName == CallPrivate::StateChange::CONNECTING ) - return CallPrivate::DaemonState::CONNECTING ; - if(stateName == CallPrivate::StateChange::RINGING ) - return CallPrivate::DaemonState::RINGING ; - if(stateName == CallPrivate::StateChange::INCOMING ) - return CallPrivate::DaemonState::RINGING ; - if(stateName == CallPrivate::StateChange::CURRENT ) - return CallPrivate::DaemonState::CURRENT ; - if(stateName == CallPrivate::StateChange::UNHOLD_CURRENT ) - return CallPrivate::DaemonState::CURRENT ; - if(stateName == CallPrivate::StateChange::HOLD ) - return CallPrivate::DaemonState::HOLD ; - if(stateName == CallPrivate::StateChange::BUSY ) - return CallPrivate::DaemonState::BUSY ; - if(stateName == CallPrivate::StateChange::FAILURE ) - return CallPrivate::DaemonState::FAILURE ; - if(stateName == CallPrivate::StateChange::INACTIVE ) - return CallPrivate::DaemonState::INACTIVE ; - if(stateName == CallPrivate::StateChange::OVER ) - return CallPrivate::DaemonState::OVER ; - - qDebug() << "stateChanged signal received with unknown state: " << stateName; - return CallPrivate::DaemonState::FAILURE ; -} //toDaemonCallState - -///Transform a conference call state to a proper call state -Call::State CallPrivate::confStatetoCallState(const QString& stateName) -{ - if ( stateName == CallPrivate::ConferenceStateChange::HOLD ) - return Call::State::CONFERENCE_HOLD; - else if ( stateName == CallPrivate::ConferenceStateChange::ACTIVE - || stateName == CallPrivate::ConferenceStateChange::DETACHED) - return Call::State::CONFERENCE; - else - return Call::State::ERROR; //Well, this may bug a little -} - -///Transform a backend state into a translated string -const QString Call::toHumanStateName(const Call::State cur) -{ - switch (cur) { - case Call::State::NEW: - //: Call state - return tr( "New" ); - case Call::State::INCOMING: - //: Call state - return tr( "Ringing" ); - case Call::State::RINGING: - //: Call state - return tr( "Calling" ); - case Call::State::CURRENT: - //: Call state - return tr( "Talking" ); - case Call::State::DIALING: - //: Call state - return tr( "Dialing" ); - case Call::State::HOLD: - //: Call state - return tr( "Hold" ); - case Call::State::FAILURE: - //: Call state - return tr( "Failed" ); - case Call::State::BUSY: - //: Call state - return tr( "Busy" ); - case Call::State::TRANSFERRED: - //: Call state - return tr( "Transfer" ); - case Call::State::TRANSF_HOLD: - //: Call state - return tr( "Transfer hold" ); - case Call::State::OVER: - //: Call state - return tr( "Over" ); - case Call::State::ERROR: - //: Call state - return tr( "Error" ); - case Call::State::CONFERENCE: - //: Call state - return tr( "Conference" ); - case Call::State::CONFERENCE_HOLD: - //: Call state - return tr( "Conference (hold)" ); - case Call::State::COUNT__: - //: Call state - return tr( "ERROR" ); - case Call::State::INITIALIZATION: - //: Call state - return tr( "Searching for" ); - case Call::State::ABORTED: - //: Call state - return tr( "Aborted" ); - case Call::State::CONNECTED: - //: Call state - return tr( "Communication established" ); - } - return QString::number(static_cast<int>(cur)); -} - -QString Call::toHumanStateName() const -{ - return toHumanStateName(state()); -} - -///Get the time (second from 1 jan 1970) when the call ended -time_t Call::stopTimeStamp() const -{ - return d_ptr->m_pStopTimeStamp; -} - -///Get the time (second from 1 jan 1970) when the call started -time_t Call::startTimeStamp() const -{ - return d_ptr->m_pStartTimeStamp; -} - -///Get the call date and time -QDateTime Call::dateTime() const -{ - if (!d_ptr->m_pDateTime) - d_ptr->m_pDateTime = new QDateTime(QDateTime::fromTime_t(startTimeStamp())); - - return *d_ptr->m_pDateTime; -} - -///Get the call date -QDate Call::date() const -{ - if (!d_ptr->m_pDateOnly) - d_ptr->m_pDateOnly = new QDate(dateTime().date()); - - return *d_ptr->m_pDateOnly; -} - -///Get the number where the call have been transferred -const QString Call::transferNumber() const -{ - if (d_ptr->m_pTransferNumber) - return d_ptr->m_pTransferNumber->uri(); - return {}; -} - -///Get the call / peer number -const QString Call::dialNumber() const -{ - if (d_ptr->m_pDialNumber) - return d_ptr->m_pDialNumber->uri(); - return {}; -} - -///Return the call id -const QString Call::historyId() const -{ - return d_ptr->m_DringId; -} - -///Return the call id -const QString Call::dringId() const -{ - Q_ASSERT(!d_ptr->m_DringId.isEmpty()); - return d_ptr->m_DringId; -} - -ContactMethod* Call::peerContactMethod() const -{ - if (d_ptr->m_pPeerContactMethod) - return d_ptr->m_pPeerContactMethod; - - if (d_ptr->m_pDialNumber) - return d_ptr->m_pDialNumber; - - return nullptr; -} - -///Get the peer name -const QString Call::peerName() const -{ - return d_ptr->m_PeerName; -} - -///Generate the best possible peer name -const QString Call::formattedName() const -{ - if (type() == Call::Type::CONFERENCE) - return tr("Conference"); - - auto name = peerContactMethod()->bestName(); - if (name.isEmpty()) - return tr("Unknown"); - return name; -} - -///If this call is encrypted, return the certificate associated with it -Certificate* Call::certificate() const -{ - return d_ptr->m_pCertificate; -} - -FlagPack<Call::HoldFlags> Call::holdFlags() const -{ - return d_ptr->m_fHoldFlags; -} - -///Generate an human readable string from the difference between StartTimeStamp and StopTimeStamp (or 'now') -QString Call::length() const -{ - if (d_ptr->m_pStartTimeStamp == d_ptr->m_pStopTimeStamp) - return QString(); //Invalid - - int nsec =0; - if (d_ptr->m_pStopTimeStamp) - nsec = stopTimeStamp() - startTimeStamp();//If the call is over - else { //Time to now - time_t curTime; - ::time(&curTime); - nsec = curTime - d_ptr->m_pStartTimeStamp; - } - if (nsec/3600) - return QString("%1:%2:%3 ").arg((nsec%(3600*24))/3600).arg(((nsec%(3600*24))%3600)/60,2,10,QChar('0')).arg(((nsec%(3600*24))%3600)%60,2,10,QChar('0')); - else - return QString("%1:%2 ").arg(nsec/60,2,10,QChar('0')).arg(nsec%60,2,10,QChar('0')); -} - -///Is this call part of history -bool Call::isHistory() const -{ - if (lifeCycleState() == Call::LifeCycleState::FINISHED && !d_ptr->m_History) - d_ptr->m_History = true; - return d_ptr->m_History; -} - -///Is this call missed -bool Call::isMissed() const -{ - return d_ptr->m_Missed; -} - -///Is the call incoming or outgoing -Call::Direction Call::direction() const -{ - return d_ptr->m_Direction; -} - -///Is the call a conference or something else -Call::Type Call::type() const -{ - return d_ptr->m_Type; -} - -bool Call::hasRemote() const -{ - return !d_ptr->m_DringId.isEmpty(); -} - -///Does this call currently has video -bool Call::hasVideo() const -{ - #ifdef ENABLE_VIDEO - if (!hasRemote()) - return false; - - return VideoRendererManager::instance().getRenderer(this) != nullptr; - #else - return false; - #endif -} - -///Get the current state -Call::State Call::state() const -{ - return d_ptr->m_CurrentState; -} - -///Translate the state into its life cycle equivalent -Call::LifeCycleState Call::lifeCycleState() const -{ - return d_ptr->metaStateMap[d_ptr->m_CurrentState]; -} - -///Get is the call is currently recording audio or video -bool Call::isAVRecording() const -{ - return lifeCycleState() == Call::LifeCycleState::PROGRESS - && (d_ptr->m_mIsRecording[ media::Media::Type::AUDIO ][ media::Media::Direction::IN ] - || d_ptr->m_mIsRecording[ media::Media::Type::AUDIO ][ media::Media::Direction::OUT ] - || d_ptr->m_mIsRecording[ media::Media::Type::VIDEO ][ media::Media::Direction::IN ] - || d_ptr->m_mIsRecording[ media::Media::Type::VIDEO ][ media::Media::Direction::OUT ]); -} - -///Get the call account id -Account* Call::account() const -{ - return d_ptr->m_Account; -} - -///This function could also be called mayBeSecure or haveChancesToBeEncryptedButWeCantTell. -bool Call::isSecure() const -{ - - return false; //No, it is not and cannot be -} //isSecure - -///Return the renderer associated with this call or nullptr -Video::Renderer* Call::videoRenderer() const -{ - #ifdef ENABLE_VIDEO - return VideoRendererManager::instance().getRenderer(this); - #else - return nullptr; - #endif -} - -void CallPrivate::videoStopped() -{ - if (auto renderer = qobject_cast<Video::Renderer*>(sender())) { - emit q_ptr->videoStopped(renderer); - } -} - -void CallPrivate::registerRenderer(Video::Renderer* renderer) -{ - #ifdef ENABLE_VIDEO - emit q_ptr->videoStarted(renderer); - - //Test logic, this is very weak, but works in a normal scenario - for (const auto d : EnumIterator<media::Media::Direction>()) - mediaFactory<media::Video>(d); - - connect(renderer, &Video::Renderer::stopped, this, &CallPrivate::videoStopped); - - #else - Q_UNUSED(renderer) - return; - #endif -} - -void CallPrivate::removeRenderer(Video::Renderer* renderer) -{ - Q_UNUSED(renderer) - //TODO handle removing the renderer during the call - return; -} - -QList<media::Media*> Call::media(media::Media::Type type, media::Media::Direction direction) const -{ - return *(d_ptr->m_mMedias[type][direction]); -} - -bool Call::hasMedia(media::Media::Type type, media::Media::Direction direction) const -{ - return d_ptr->m_mMedias[type][direction]->size(); -} - -bool Call::hasRecording(media::Media::Type type, media::Media::Direction direction) const -{ - return d_ptr->m_mRecordings[type][direction]->size(); -} - -bool Call::isRecording(media::Media::Type type, media::Media::Direction direction) const -{ - return d_ptr->m_mIsRecording[type][direction]; -} - -QList<media::Recording*> Call::recordings(media::Media::Type type, media::Media::Direction direction) const -{ - //Note that the recording are not Media attributes to avoid keeping "terminated" media - //for history call. - return *d_ptr->m_mRecordings[type][direction]; -} - -/** - * An iffecient way to list all media. If this ever become used elsewhere, - * add caching. - */ -QList<media::Media*> Call::allMedia() const -{ - QList<media::Media*> ret; - - for (const auto t : EnumIterator<media::Media::Type>() ) { - for (const auto d : EnumIterator<media::Media::Direction>() ) { - foreach(media::Media* m, *(d_ptr->m_mMedias[t][d])) - ret << m; - } - } - - return ret; -} - -/***************************************************************************** - * * - * Media type inference utils * - * * - ****************************************************************************/ - -/** - * This function is used to map template type to media type - * it generate unique type identifier - */ -int MediaTypeInference::genId() { - static int currentId = 0; - return ++currentId; -} - -/** - * Every time new ids are generated (that can be done some time), this map is - * updated to map those type ids to Media::Type - * - * It could be extended to store some operations into lambdas too, but for - * now the safeMediaCreator switch is the only place where this would be useful, - * so there is very little point to do that. - */ -QHash<int, media::Media::Type>& MediaTypeInference::typeMap(bool regen) { - static bool isInit = false; - //Try to map T to media::Media::Type then use this to retrieve and cast the media - static QHash<int, media::Media::Type> sTypeMap; - if (!isInit || regen) { - isInit = true; - REGISTER_MEDIA() - } - return sTypeMap; -} - -/** - * Create, register and connect new media to a call. - */ -template<typename T> -T* CallPrivate::mediaFactory(media::Media::Direction dir) -{ - T* m = new T(q_ptr, dir); - (*m_mMedias[MediaTypeInference::getType<T>()][dir]) << m; - const auto cb = [this,m](const media::Media::State s, const media::Media::State p) { - if (m) { - emit q_ptr->mediaStateChanged(m,s,p); - } - else - Q_ASSERT(false); - }; - - connect(m, &media::Media::stateChanged, cb); - emit q_ptr->mediaAdded(m); - - return m; -} - -/** - * As mediaFactory is private, expose this proxy and let the template methods - * do a static cast to re-create the right type. Given how it is using - * MediaTypeInference, it is safe-ish. - */ -media::Media* MediaTypeInference::safeMediaCreator(Call* c, media::Media::Type t, media::Media::Direction d) -{ - switch(t) { - case media::Media::Type::AUDIO: - return c->d_ptr->mediaFactory<media::Audio>(d); - case media::Media::Type::VIDEO: - return c->d_ptr->mediaFactory<media::Video>(d); - case media::Media::Type::TEXT : - return c->d_ptr->mediaFactory<media::Text>(d); - case media::Media::Type::FILE : - return c->d_ptr->mediaFactory<media::File>(d); - case media::Media::Type::COUNT__: - break; - } - return nullptr; -} - -/***************************************************************************** - * * - * Setters * - * * - ****************************************************************************/ - -///Set the transfer number -void Call::setTransferNumber(const QString& number) -{ - if (!d_ptr->m_pTransferNumber) - d_ptr->m_pTransferNumber = new TemporaryContactMethod(); - d_ptr->m_pTransferNumber->setUri(number); -} - -///Set the call number -void Call::setDialNumber(const QString& number) -{ - //This is not supposed to happen, but this is not a serious issue if it does - if (lifeCycleState() != Call::LifeCycleState::CREATION) { - qDebug() << "Trying to set a dial number to a non-dialing call, doing nothing"; - return; - } - - const bool isEmpty = number.isEmpty(); - - d_ptr->m_pDialNumber->setUri(number); - emit dialNumberChanged(d_ptr->m_pDialNumber->uri()); - emit changed(); - - //Make sure the call is now in the right state - if ((!isEmpty) && state() == Call::State::NEW) - d_ptr->changeCurrentState(Call::State::DIALING); - else if (isEmpty && state() == Call::State::DIALING) - d_ptr->changeCurrentState(Call::State::NEW); -} - -///Set the dial number from a full phone number -void Call::setDialNumber(const ContactMethod* number) -{ - if (!number) - return; - setDialNumber(number->uri()); -} - -void Call::setPeerContactMethod(ContactMethod* cm) -{ - //Change the peerContactMethod only when creating a Call - if (!cm || lifeCycleState() != Call::LifeCycleState::CREATION) { - qDebug() << "Trying to change the contact method on a non-dialing call"; - return; - } - d_ptr->m_pPeerContactMethod = cm; - setDialNumber(cm->uri()); -} - -///Set the recording path -void CallPrivate::setRecordingPath(const QString& path) -{ -} - -///Set peer name -void Call::setPeerName(const QString& name) -{ - d_ptr->m_PeerName = name; - - // its possible that this is not set at the beginning of a call, so we should update the CM here - if (peerContactMethod()) - peerContactMethod()->incrementAlternativeName(name, startTimeStamp()); -} - -///Set the account (DIALING only, may be ignored) -void Call::setAccount( Account* account) -{ - if (lifeCycleState() == Call::LifeCycleState::CREATION) - d_ptr->m_Account = account; -} - -void Call::setParentCall(Call* call) -{ - d_ptr->m_pParentCall = call; -} - -/***************************************************************************** - * * - * Mutator * - * * - ****************************************************************************/ - -///The call state just changed (by the daemon) -Call::State CallPrivate::stateChanged(const QString& newStateName) -{ - const Call::State previousState = m_CurrentState; - if (q_ptr->type() != Call::Type::CONFERENCE) { - CallPrivate::DaemonState dcs = toDaemonCallState(newStateName); - if (dcs == CallPrivate::DaemonState::COUNT__ || m_CurrentState == Call::State::COUNT__) { - qDebug() << "Error: Invalid state change"; - return Call::State::FAILURE; - } -// if (previousState == stateChangedStateMap[m_CurrentState][dcs]) { -// #ifndef NDEBUG -// qDebug() << "Trying to change state with the same state" << previousState; -// #endif -// return previousState; -// } - - try { - //Validate if the transition respect the expected life cycle - if (!metaStateTransitionValidationMap[stateChangedStateMap[m_CurrentState][dcs]][q_ptr->lifeCycleState()]) { - qWarning() << "Unexpected state transition from" << q_ptr->state() << "to" << stateChangedStateMap[m_CurrentState][dcs]; - Q_ASSERT(false); - } - changeCurrentState(stateChangedStateMap[m_CurrentState][dcs]); - - // TODO: this is a hack as the flags should be set in functions specified - // in the state transition matrix, not here - if (m_CurrentState == Call::State::HOLD) { - if ( !(m_fHoldFlags & Call::HoldFlags::OUT) ) { - const FlagPack<Call::HoldFlags> old = m_fHoldFlags; - m_fHoldFlags |= Call::HoldFlags::OUT; - emit q_ptr->holdFlagsChanged(m_fHoldFlags, old); - } - } else { - // not hold, make sure to take away the flag - if (m_fHoldFlags & Call::HoldFlags::OUT) { - const FlagPack<Call::HoldFlags> old = m_fHoldFlags; - m_fHoldFlags ^= Call::HoldFlags::OUT; - emit q_ptr->holdFlagsChanged(m_fHoldFlags, old); - } - } - } - catch(Call::State& state) { - qDebug() << "State change failed (stateChangedStateMap)" << state; - FORCE_ERROR_STATE_P() - return m_CurrentState; - } - catch(CallPrivate::DaemonState& state) { - qDebug() << "State change failed (stateChangedStateMap)" << state; - FORCE_ERROR_STATE_P() - return m_CurrentState; - } - catch (...) { - qDebug() << "State change failed (stateChangedStateMap) other";; - FORCE_ERROR_STATE_P() - return m_CurrentState; - } - - MapStringString details = getCallDetailsCommon(m_DringId); - updateOutgoingMedia(details); - - if (!details[DRing::Call::Details::DISPLAY_NAME].isEmpty() - and ( details[DRing::Call::Details::DISPLAY_NAME] != m_PeerName) ) - q_ptr->setPeerName(details[DRing::Call::Details::DISPLAY_NAME]); - - //Load the certificate if it's now available - if (!q_ptr->certificate() && !details[DRing::TlsTransport::TLS_PEER_CERT].isEmpty()) { - m_pCertificate = CertificateModel::instance().getCertificateFromId(details[DRing::TlsTransport::TLS_PEER_CERT], q_ptr->account()); - } - - try { - (this->*(stateChangedFunctionMap[previousState][dcs]))(); - } - catch(Call::State& state) { - qDebug() << "State change failed (stateChangedFunctionMap)" << state; - FORCE_ERROR_STATE_P() - return m_CurrentState; - } - catch(CallPrivate::DaemonState& state) { - qDebug() << "State change failed (stateChangedFunctionMap)" << state; - FORCE_ERROR_STATE_P() - return m_CurrentState; - } - catch (...) { - qDebug() << "State change failed (stateChangedFunctionMap) other";; - FORCE_ERROR_STATE_P() - return m_CurrentState; - } - } - else { - //Until now, it does not worth using stateChangedStateMap, conferences are quite simple - //update 2014: Umm... wrong - m_CurrentState = confStatetoCallState(newStateName); //TODO don't do this - emit q_ptr->stateChanged(m_CurrentState,previousState); - - //TODO find a way to handle media for conferences to rewrite them as communication group - if (CallPrivate::metaStateMap[m_CurrentState] != CallPrivate::metaStateMap[previousState]) - emit q_ptr->lifeCycleStateChanged(CallPrivate::metaStateMap[m_CurrentState],CallPrivate::metaStateMap[previousState]); - - } - if (q_ptr->lifeCycleState() != Call::LifeCycleState::CREATION && m_pDialNumber) { - if (!m_pPeerContactMethod) { - m_pPeerContactMethod = PhoneDirectoryModel::instance().fromTemporary(m_pDialNumber); - } - m_pDialNumber->deleteLater(); - m_pDialNumber = nullptr; - } - emit q_ptr->changed(); - qDebug() << "Calling stateChanged " << newStateName << " -> " << toDaemonCallState(newStateName) << " on call with state " << previousState << ". Become " << m_CurrentState; - return m_CurrentState; -} //stateChanged - -void CallPrivate::performAction(Call::State previousState, Call::Action action) -{ - changeCurrentState(actionPerformedStateMap[previousState][action]); -} - -void CallPrivate::performActionCallback(Call::State previousState, Call::Action action) -{ - (this->*(actionPerformedFunctionMap[previousState][action]))(); -} - -///An account have been performed -Call::State Call::performAction(Call::Action action) -{ - const Call::State previousState = d_ptr->m_CurrentState; - -// if (actionPerformedStateMap[previousState][action] == previousState) { -// #ifndef NDEBUG -// qDebug() << "Trying to change state with the same state" << previousState; -// #endif -// return previousState; -// } - - //update the state - try { - d_ptr->performAction(previousState, action); - } - catch(Call::State& state) { - qDebug() << "State change failed (actionPerformedStateMap)" << state; - FORCE_ERROR_STATE() - return Call::State::ERROR; - } - catch (...) { - qDebug() << "State change failed (actionPerformedStateMap) other";; - FORCE_ERROR_STATE() - return d_ptr->m_CurrentState; - } - - //execute the action associated with this transition - try { - d_ptr->performActionCallback(previousState, action); - } - catch(Call::State& state) { - qDebug() << "State change failed (actionPerformedFunctionMap)" << state; - FORCE_ERROR_STATE() - return Call::State::ERROR; - } - catch(Call::Action& action) { - qDebug() << "State change failed (actionPerformedFunctionMap)" << action; - FORCE_ERROR_STATE() - return Call::State::ERROR; - } - catch (...) { - qDebug() << "State change failed (actionPerformedFunctionMap) other";; - FORCE_ERROR_STATE() - return d_ptr->m_CurrentState; - } - qDebug() << "Calling action " << action << " on " << this << " with state " << previousState << ". Become " << d_ptr->m_CurrentState; - return d_ptr->m_CurrentState; -} //actionPerformed - -///Change the state, do not abuse of this, but it is necessary for error cases -void CallPrivate::changeCurrentState(Call::State newState) -{ - if (newState == Call::State::COUNT__) { - qDebug() << "Error: Call reach invalid state"; - FORCE_ERROR_STATE_P() - throw newState; - } - - if (m_CurrentState == newState) { - qDebug() << "Origin and destination states are identical" << m_CurrentState << newState << "doing nothing" << q_ptr; - return; - } - - const Call::State previousState = m_CurrentState; - - m_CurrentState = newState; - qDebug() << "State changing from"<<previousState << "to" << m_CurrentState << "on" << q_ptr; - - emit q_ptr->stateChanged(newState, previousState); - - if (CallPrivate::metaStateMap[newState] != CallPrivate::metaStateMap[previousState]) { - const Call::LifeCycleState oldLCS = CallPrivate::metaStateMap[ previousState ]; - const Call::LifeCycleState newLCS = CallPrivate::metaStateMap[ newState ]; - - //Call the LifeCycleState callback - (this->*m_mLifeCycleStateChanges[newLCS])(); - - emit q_ptr->lifeCycleStateChanged(newLCS, oldLCS); - } - - emit q_ptr->changed(); - - initTimer(); - - // If the call failed, start the timer for 1 second and refuse the call. - if (q_ptr->state() == Call::State::FAILURE) { - if (!m_pTimer) { - m_pTimer = new QTimer(this); - m_pTimer->setInterval(1000); - connect(m_pTimer,SIGNAL(timeout()),this,SLOT(refuseAfterFailure())); - } - if (!m_pTimer->isActive()) { - m_pTimer->start(); - } - } - - if (q_ptr->lifeCycleState() == Call::LifeCycleState::FINISHED) - emit q_ptr->isOver(); - -} - -void CallPrivate::initMedia() -{ - //Always assume there is an audio media, even if this is untrue - for (const auto d : EnumIterator<media::Media::Direction>()) - mediaFactory<media::Audio>(d); -} - -void CallPrivate::terminateMedia() -{ - //Delete remaining media - for (const auto t : EnumIterator<media::Media::Type>() ) { - for (const auto d : EnumIterator<media::Media::Direction>() ) { - for (auto m : q_ptr->media(t,d) ) { - m << media::Media::Action::TERMINATE; - m_mMedias[t][d]->removeAll(m); - //TODO keep the media for history visualization purpose if it has a recording - delete m; - } - } - } -} - -///Set the start timestamp and update the cache -void CallPrivate::setStartTimeStamp(time_t stamp) -{ - m_pStartTimeStamp = stamp; -} - -void CallPrivate::setStartTimeStamp() -{ - time_t curTime; - ::time(&curTime); - setStartTimeStamp(curTime); -} - -bool Call::hasParentCall() const -{ - return (d_ptr->m_pParentCall); -} - -bool Call::joinToParent() -{ - return false; -} - -QMimeData* Call::mimePayload() const -{ - return RingMimes::payload(this, nullptr, nullptr); -} - -/***************************************************************************** - * * - * Automate function * - * * - ****************************************************************************/ -///@warning DO NOT TOUCH THAT, THEY ARE CALLED FROM AN AUTOMATE, HIGH FRAGILITY - -///Do nothing (literally) -void CallPrivate::nothing() -{ - //nop -} - -void CallPrivate::error() -{ - if (q_ptr->videoRenderer()) { - //Well, in this case we have no choice, it still doesn't belong here - q_ptr->videoRenderer()->stopRendering(); - } - throw QString("There was an error handling your call, please restart Ring. If you encounter this problem often, \ - please open Ring in a terminal and send the last 100 lines before this message in a bug report at \ - https://tuleap.ring.cx"); -} - -///Change history state to failure -void CallPrivate::failure() -{ - m_Missed = true; - //This is how it always was done - //The main point is to leave the call in the CallList - start(); -} - -///Accept the call -void CallPrivate::accept() -{ - Q_ASSERT_IS_IN_PROGRESS - - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Accepting call. callId : " << q_ptr << "ConfId:" << q_ptr; - Q_NOREPLY callManager.accept(m_DringId); - setStartTimeStamp(); - m_Direction = Call::Direction::INCOMING; -} - -///Refuse the call -void CallPrivate::refuse() -{ - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Refusing call. callId : " << q_ptr << "ConfId:" << q_ptr; - const bool ret = callManager.refuse(m_DringId); - setStartTimeStamp(); - m_Missed = true; - - //If the daemon crashed then re-spawned when a call is ringing, this happen. - if (!ret) - FORCE_ERROR_STATE_P() -} - -///Accept the transfer -void CallPrivate::acceptTransf() -{ - Q_ASSERT_IS_IN_PROGRESS - - if (!m_pTransferNumber) { - qDebug() << "Trying to transfer to no one"; - return; - } - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Accepting call and transferring it to number : " << m_pTransferNumber->uri() << ". callId : " << q_ptr << "ConfId:" << q_ptr; - callManager.accept(m_DringId); - Q_NOREPLY callManager.transfer(m_DringId, m_pTransferNumber->uri()); -} - -///Put the call on hold -void CallPrivate::acceptHold() -{ - Q_ASSERT_IS_IN_PROGRESS - - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Accepting call and holding it. callId : " << q_ptr << "ConfId:" << q_ptr; - callManager.accept(m_DringId); - Q_NOREPLY callManager.hold(m_DringId); - m_Direction = Call::Direction::INCOMING; -} - -///Hang up -void CallPrivate::hangUp() -{ - Q_ASSERT_IS_IN_PROGRESS - - CallManagerInterface & callManager = CallManager::instance(); - time_t curTime; - ::time(&curTime); - m_pStopTimeStamp = curTime; - qDebug() << "Hanging up call. callId : " << q_ptr << "ConfId:" << q_ptr; - bool ret; - if (q_ptr->type() != Call::Type::CONFERENCE) - ret = callManager.hangUp(m_DringId); - else - ret = callManager.hangUpConference(m_DringId); - if (!ret) { //Can happen if the daemon crash and open again - qDebug() << "Error: Invalid call, the daemon may have crashed"; - changeCurrentState(Call::State::OVER); - } - if (m_pTimer) - m_pTimer->stop(); -} - -///Remove the call without contacting the daemon -void CallPrivate::remove() -{ - if (q_ptr->lifeCycleState() != Call::LifeCycleState::FINISHED) - FORCE_ERROR_STATE_P() - - CallManagerInterface & callManager = CallManager::instance(); - - //HACK Call hang up again to make sure the busytone stop, this should - //return true or false, both are valid, no point to check the result - if (q_ptr->type() != Call::Type::CONFERENCE) - callManager.hangUp(q_ptr->dringId()); - else - callManager.hangUpConference(q_ptr->dringId()); - - emit q_ptr->isOver(); - emit q_ptr->stateChanged(m_CurrentState, m_CurrentState); - emit q_ptr->changed(); -} - -///Abort this call (never notify the daemon there was a call) -void CallPrivate::abort() -{ - -} - -/** - * Send your profile to the peer, assume the other use RING - * - * If he doesn't then an "unsupported media" error will be - * sent by the peer. - * - * @todo Do not try to re-send profiles to that CM (save in history?) - */ -void CallPrivate::sendProfile() -{ -} - -///Cancel this call -void CallPrivate::cancel() -{ - //This one can be over if the peer server failed to comply with the correct sequence - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Canceling call. callId : " << q_ptr << "ConfId:" << q_ptr; - emit q_ptr->dialNumberChanged(QString()); - if (!callManager.hangUp(m_DringId)) { - qWarning() << "HangUp failed, the call was probably already over"; - changeCurrentState(Call::State::OVER); - } -} - -///Put on hold -void CallPrivate::hold() -{ - Q_ASSERT_IS_IN_PROGRESS - - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Holding call. callId : " << q_ptr << "ConfId:" << q_ptr; - - if ( m_fHoldFlags & Call::HoldFlags::OUT ) { - qWarning() << "Hold flags indicate the call is already on hold."; - } else { - const FlagPack<Call::HoldFlags> old = m_fHoldFlags; - m_fHoldFlags |= Call::HoldFlags::OUT; - emit q_ptr->holdFlagsChanged(m_fHoldFlags, old); - } - - if (q_ptr->type() != Call::Type::CONFERENCE) - Q_NOREPLY callManager.hold(q_ptr->dringId()); - else - Q_NOREPLY callManager.holdConference(q_ptr->dringId()); -} - -///Start the call -void CallPrivate::call() -{ - Q_ASSERT_IS_IN_PROGRESS; - auto peerCM = q_ptr->peerContactMethod(); - - // Calls to empty URI should not be allowed, dring will go crazy - if (peerCM->uri().isEmpty()) { - qDebug() << "Trying to call an empty URI"; - changeCurrentState(Call::State::ABORTED); - if (!m_pDialNumber) - emit q_ptr->dialNumberChanged(QString()); - else { - m_pDialNumber->deleteLater(); - m_pDialNumber = nullptr; - } - q_ptr->setPeerName(tr("Aborted")); - emit q_ptr->changed(); - return; - } - - // Try to set the account from the associated ContactMethod - if (auto tryingAcc = peerCM->account()) { - // make sure account exist in the model and that it's READY - if (AccountModel::instance().getById(tryingAcc->id()) && - (tryingAcc->registrationState() == Account::RegistrationState::READY)) - m_Account = tryingAcc; - } - - // Normal case - qDebug() << "Calling " << peerCM->uri() << " with account " << m_Account - << ", CallId: " << q_ptr - << ", ConfId: " << q_ptr; - m_Direction = Call::Direction::OUTGOING; - - // Warning: m_pDialNumber can become nullptr when linking directly - URI uri {peerCM->uri()}; - - // Better late than never. Set the scheme. - if (m_Account && m_Account->protocol() == Account::Protocol::RING && - uri.schemeType() == URI::SchemeType::NONE && - uri.protocolHint() != URI::ProtocolHint::RING) { - uri.setSchemeType(URI::SchemeType::RING); - } - - if (!m_pPeerContactMethod) { - m_pPeerContactMethod = PhoneDirectoryModel::instance().getNumber(uri, q_ptr->account()); - } - - // m_pDialNumber is now discarded - m_pDialNumber->deleteLater(); - m_pDialNumber = nullptr; - - //set the start timestamp to now, even if the call fails immediately, so that it has a timestamp - //this behaviour is the same as if the call intialized in the daemon but then failed shortly after - setStartTimeStamp(); - - //Refresh peerCM - peerCM = q_ptr->peerContactMethod(); - peerCM->addCall(q_ptr); - - // dring can print "No suitable account to create outgoing call" if the - // URI isn't properly formatted (like sip:foobar). - if (m_Account && m_Account->protocol() == Account::Protocol::RING && uri.protocolHint() != URI::ProtocolHint::RING) { - qWarning() << "The URI isn't a RingId. It is possible the call wont work" << uri.full(); - } - - m_DringId = CallManager::instance().placeCall(m_Account->id(), uri.full()); - - // This can happen when the daemon cannot allocate memory - if (m_DringId.isEmpty()) { - changeCurrentState(Call::State::FAILURE); - qWarning() << "Creating the call to " << peerCM->uri() << " failed"; - m_DringId = "FAILED"; - return; - } - setObjectName("Call:"+m_DringId); - - connect(peerCM, SIGNAL(presentChanged(bool)), this, SLOT(updated())); - - emit q_ptr->dialNumberChanged(QString()); -} - -///Transfer the call -void CallPrivate::transfer() -{ - Q_ASSERT_IS_IN_PROGRESS; - - if (!m_pTransferNumber) - return; - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Transferring call to number : " << m_pTransferNumber->uri() << ". callId : " << q_ptr; - Q_NOREPLY callManager.transfer(m_DringId, m_pTransferNumber->uri()); - time_t curTime; - ::time(&curTime); - m_pStopTimeStamp = curTime; -} - -///Unhold the call -void CallPrivate::unhold() -{ - Q_ASSERT_IS_IN_PROGRESS - - CallManagerInterface & callManager = CallManager::instance(); - qDebug() << "Unholding call. callId : " << q_ptr << "ConfId:" << q_ptr; - - if ( !(m_fHoldFlags & Call::HoldFlags::OUT) ) { - qWarning() << "Hold flags indicate the call is not on hold."; - } else { - const FlagPack<Call::HoldFlags> old = m_fHoldFlags; - m_fHoldFlags ^= Call::HoldFlags::OUT; - emit q_ptr->holdFlagsChanged(m_fHoldFlags, old); - } - - if (q_ptr->type() != Call::Type::CONFERENCE) - Q_NOREPLY callManager.unhold(q_ptr->dringId()); - else - Q_NOREPLY callManager.unholdConference(q_ptr->dringId()); -} - -///React where a peer hold event happen -void CallPrivate::peerHoldChanged(bool onPeerHold) -{ - if (((m_fHoldFlags & Call::HoldFlags::IN).value() > 0) == onPeerHold) - return; - - const FlagPack<Call::HoldFlags> old = m_fHoldFlags; - - m_fHoldFlags ^= Call::HoldFlags::IN; - - emit q_ptr->holdFlagsChanged(m_fHoldFlags, old); - - emit q_ptr->changed(); -} - -///Record the call -void CallPrivate::toggleAudioRecord() -{ - CallManagerInterface & callManager = CallManager::instance(); - const bool wasRecording = m_mIsRecording[ media::Media::Type::AUDIO ][media::Media::Direction::IN]; - qDebug() << "Setting record " << !wasRecording << " for call. callId : " << q_ptr << "ConfId:" << q_ptr; - - const bool isRec = callManager.toggleRecording(q_ptr->dringId()); - - m_mIsRecording[ media::Media::Type::AUDIO ].setAt( media::Media::Direction::IN , isRec); - m_mIsRecording[ media::Media::Type::AUDIO ].setAt( media::Media::Direction::OUT , isRec); -} - -///Record the call -void CallPrivate::toggleVideoRecord() -{ - //TODO upgrade once the video recording is implemented - CallManagerInterface & callManager = CallManager::instance(); - const bool wasRecording = m_mIsRecording[ media::Media::Type::VIDEO ][media::Media::Direction::IN]; - qDebug() << "Setting record " << !wasRecording << " for call. callId : " << q_ptr << "ConfId:" << q_ptr; - - const bool isRec = callManager.toggleRecording(q_ptr->dringId()); - - m_mIsRecording[ media::Media::Type::VIDEO ].setAt( media::Media::Direction::IN , isRec); - m_mIsRecording[ media::Media::Type::VIDEO ].setAt( media::Media::Direction::OUT , isRec); -} - -///Start the timer -void CallPrivate::start() -{ - qDebug() << "Starting call. callId : " << q_ptr << "ConfId:" << q_ptr; - emit q_ptr->changed(); - if (m_pDialNumber) { - if (!m_pPeerContactMethod) { - m_pPeerContactMethod = PhoneDirectoryModel::instance().fromTemporary(m_pDialNumber); - } - m_pDialNumber->deleteLater(); - m_pDialNumber = nullptr; - } - setStartTimeStamp(); - initTimer(); -} - -///Toggle the timer -void CallPrivate::startStop() -{ - qDebug() << "Starting and stoping call. callId : " << q_ptr << "ConfId:" << q_ptr; - setStartTimeStamp(); - m_pStopTimeStamp = m_pStartTimeStamp; - m_Missed = true; -} - -///Stop the timer -void CallPrivate::stop() -{ - qDebug() << "Stoping call. callId : " << q_ptr << "ConfId:" << q_ptr; - time_t curTime; - ::time(&curTime); - m_pStopTimeStamp = curTime; -} - -///Handle error instead of crashing -void CallPrivate::startWeird() -{ - qDebug() << "Starting call. callId : " << q_ptr << "ConfId:" << q_ptr; - setStartTimeStamp(); - qDebug() << "Warning : call " << q_ptr << " had an unexpected transition of state at its start."; -} - -///Print a warning -void CallPrivate::warning() -{ - qWarning() << "Warning : call " << q_ptr << " had an unexpected transition of state.(" << m_CurrentState << ")"; - switch (m_CurrentState) { - case Call::State::FAILURE : - case Call::State::ERROR : - case Call::State::COUNT__ : - //If not stopped, then the counter will keep going - //Getting here indicate something wrong happened - //It can be normal, aka, an invalid URI such as '><' - // or an Ring-KDE bug - stop(); - break; - case Call::State::TRANSFERRED : - case Call::State::TRANSF_HOLD : - case Call::State::DIALING : - case Call::State::NEW : - case Call::State::INITIALIZATION : - case Call::State::INCOMING : - case Call::State::RINGING : - case Call::State::CURRENT : - case Call::State::HOLD : - case Call::State::BUSY : - case Call::State::OVER : - case Call::State::ABORTED : - case Call::State::CONNECTED : - case Call::State::CONFERENCE : - case Call::State::CONFERENCE_HOLD: - break; - } -} - -/***************************************************************************** - * * - * Keyboard handling * - * * - ****************************************************************************/ - -///Input text on the call item -void Call::appendText(const QString& str) -{ - TemporaryContactMethod* editNumber = nullptr; - switch (d_ptr->m_CurrentState) { - case Call::State::TRANSFERRED : - case Call::State::TRANSF_HOLD : - editNumber = d_ptr->m_pTransferNumber; - break; - case Call::State::DIALING : - case Call::State::NEW : { - const bool wasEmpty = (!editNumber) ||editNumber->uri().isEmpty(); - editNumber = d_ptr->m_pDialNumber; - const bool isEmpty = str.isEmpty(); - - if (wasEmpty != isEmpty) - d_ptr->changeCurrentState(isEmpty ? Call::State::NEW : Call::State::DIALING); - } - break; - case Call::State::INITIALIZATION: - case Call::State::CONNECTED: - case Call::State::INCOMING: - case Call::State::RINGING: - case Call::State::CURRENT: - case Call::State::HOLD: - case Call::State::FAILURE: - case Call::State::BUSY: - case Call::State::OVER: - case Call::State::ABORTED: - case Call::State::ERROR: - case Call::State::CONFERENCE: - case Call::State::CONFERENCE_HOLD: - case Call::State::COUNT__: - qDebug() << "Backspace on call not editable. Doing nothing."; - return; - } - - if (editNumber) { - editNumber->setUri(editNumber->uri()+str); - if (lifeCycleState() == Call::LifeCycleState::CREATION) - emit dialNumberChanged(editNumber->uri()); - } - else - qDebug() << "TemporaryContactMethod not defined"; - - emit changed(); -} - -///Remove the last character -void Call::backspaceItemText() -{ - TemporaryContactMethod* editNumber = nullptr; - - switch (d_ptr->m_CurrentState) { - case Call::State::TRANSFERRED : - case Call::State::TRANSF_HOLD : - editNumber = d_ptr->m_pTransferNumber; - break; - case Call::State::NEW: - case Call::State::DIALING : { - const bool wasEmpty = (!editNumber) ||editNumber->uri().isEmpty(); - editNumber = d_ptr->m_pDialNumber; - const bool isEmpty = editNumber->uri().isEmpty(); - - if (wasEmpty != isEmpty) - d_ptr->changeCurrentState(isEmpty ? Call::State::NEW : Call::State::DIALING); - - } - break; - case Call::State::INITIALIZATION: - case Call::State::CONNECTED: - case Call::State::INCOMING: - case Call::State::RINGING: - case Call::State::CURRENT: - case Call::State::HOLD: - case Call::State::FAILURE: - case Call::State::BUSY: - case Call::State::ABORTED: - case Call::State::OVER: - case Call::State::ERROR: - case Call::State::CONFERENCE: - case Call::State::CONFERENCE_HOLD: - case Call::State::COUNT__: - qDebug() << "Backspace on call not editable. Doing nothing."; - return; - } - if (editNumber) { - QString text = editNumber->uri(); - const int textSize = text.size(); - if(textSize > 0) { - editNumber->setUri(text.remove(textSize-1, 1)); - emit changed(); - } - else { - d_ptr->changeCurrentState(Call::State::ABORTED); - } - } - else - qDebug() << "TemporaryContactMethod not defined"; -} - -///Reset the string a dialing or transfer call -void Call::reset() -{ - TemporaryContactMethod* editNumber = nullptr; - - switch (d_ptr->m_CurrentState) { - case Call::State::TRANSFERRED : - case Call::State::TRANSF_HOLD : - editNumber = d_ptr->m_pTransferNumber; - break; - case Call::State::DIALING : - case Call::State::NEW : - editNumber = d_ptr->m_pDialNumber; - d_ptr->changeCurrentState( Call::State::NEW ); - break; - case Call::State::INITIALIZATION : - case Call::State::CONNECTED : - case Call::State::INCOMING : - case Call::State::RINGING : - case Call::State::CURRENT : - case Call::State::HOLD : - case Call::State::FAILURE : - case Call::State::BUSY : - case Call::State::OVER : - case Call::State::ABORTED : - case Call::State::ERROR : - case Call::State::CONFERENCE : - case Call::State::CONFERENCE_HOLD : - case Call::State::COUNT__: - qDebug() << "Cannot reset" << d_ptr->m_CurrentState << "calls"; - return; - } - if (editNumber) { - editNumber->setUri(QString()); - } -} - -/***************************************************************************** - * * - * SLOTS * - * * - ****************************************************************************/ - -void CallPrivate::updated() -{ - emit q_ptr->changed(); -} - -void CallPrivate::refuseAfterFailure() -{ - if (m_pTimer) { - m_pTimer->stop(); - delete m_pTimer; - m_pTimer = nullptr; - q_ptr->performAction(Call::Action::REFUSE); - } -} - -///Check if creating a timer is necessary -void CallPrivate::initTimer() -{ - if (q_ptr->lifeCycleState() == Call::LifeCycleState::PROGRESS - || q_ptr->lifeCycleState() == Call::LifeCycleState::INITIALIZATION) { - if (!m_pTimer) { - m_pTimer = new QTimer(this); - m_pTimer->setInterval(1000); - connect(m_pTimer,SIGNAL(timeout()),this,SLOT(updated())); - } - if (!m_pTimer->isActive()) - m_pTimer->start(); - } - else if (m_pTimer && q_ptr->lifeCycleState() != Call::LifeCycleState::PROGRESS) { - m_pTimer->stop(); - delete m_pTimer; - m_pTimer = nullptr; - } -} - -QVariant Call::roleData(Call::Role role) const -{ - return roleData(static_cast<int>(role)); -} - -///Common source for model data roles -QVariant Call::roleData(int role) const -{ - const Person* ct = peerContactMethod()?peerContactMethod()->contact():nullptr; - switch (role) { - case static_cast<int>(Ring::Role::Name): - case static_cast<int>(Call::Role::Name): - case Qt::DisplayRole: - return formattedName(); - case Qt::ToolTipRole: - return tr("Account: ") + (account()?account()->alias():QString()); - case Qt::EditRole: - return dialNumber(); - case static_cast<int>(Ring::Role::Number): - case static_cast<int>(Call::Role::Number): - return peerContactMethod()->bestId(); - case static_cast<int>(Ring::Role::URI): - return peerContactMethod()->uri(); - case Qt::DecorationRole: - return GlobalInstances::pixmapManipulator().decorationRole(this); - case static_cast<int>(Call::Role::Direction): - return QVariant::fromValue(d_ptr->m_Direction); - case static_cast<int>(Call::Role::Date): - return (int)startTimeStamp(); - case static_cast<int>(Ring::Role::Length): - case static_cast<int>(Call::Role::Length): - return length(); - case static_cast<int>(Call::Role::FormattedDate): - if (d_ptr->m_FormattedDate.isEmpty()) - d_ptr->m_FormattedDate = dateTime().toString(); - return d_ptr->m_FormattedDate; - case static_cast<int>(Call::Role::DateOnly): - return date(); - case static_cast<int>(Call::Role::DateTime): - return dateTime(); - case static_cast<int>(Call::Role::HasAVRecording): - return d_ptr->m_mRecordings[media::Media::Type::AUDIO][media::Media::Direction::IN]->size() - + d_ptr->m_mRecordings[media::Media::Type::AUDIO][media::Media::Direction::IN]->size() > 0; - case static_cast<int>(Call::Role::IsAVRecording): - return d_ptr->m_mIsRecording[media::Media::Type::AUDIO][media::Media::Direction::IN] - || d_ptr->m_mIsRecording[media::Media::Type::AUDIO][media::Media::Direction::IN]; - case static_cast<int>(Call::Role::Filter): { - QString normStripppedC; - foreach(QChar char2,(static_cast<int>(direction())+'\n'+roleData(Call::Role::Name).toString()+'\n'+ - roleData(Call::Role::Number).toString()).toLower().normalized(QString::NormalizationForm_KD) ) { - if (!char2.combiningClass()) - normStripppedC += char2; - } - return normStripppedC; - } - case static_cast<int>(Call::Role::FuzzyDate): - return QVariant(); - case static_cast<int>(Call::Role::IsBookmark): - return false; - case static_cast<int>(Call::Role::Security): - return isSecure(); - case static_cast<int>(Call::Role::Department): - return ct?ct->department():QVariant(); - case static_cast<int>(Call::Role::Email): - return ct?ct->preferredEmail():QVariant(); - case static_cast<int>(Call::Role::Organisation): - return ct?ct->organization():QVariant(); - case static_cast<int>(Ring::Role::Object): - case static_cast<int>(Call::Role::Object): - return QVariant::fromValue(const_cast<Call*>(this)); - case static_cast<int>(Ring::Role::ObjectType): - return QVariant::fromValue(Ring::ObjectType::Call); - case static_cast<int>(Call::Role::ContactMethod): - return QVariant::fromValue(peerContactMethod()); - case static_cast<int>(Call::Role::Photo): - return ct?ct->photo():QVariant(); - case static_cast<int>(Ring::Role::State): - case static_cast<int>(Call::Role::State): - return QVariant::fromValue(state()); - case static_cast<int>(Call::Role::StartTime): - return (int) d_ptr->m_pStartTimeStamp; - case static_cast<int>(Call::Role::StopTime): - return (int) d_ptr->m_pStopTimeStamp; - case static_cast<int>(Call::Role::IsPresent): - case static_cast<int>(Ring::Role::IsPresent): - return peerContactMethod()->isPresent(); - case static_cast<int>(Call::Role::IsTracked): - return peerContactMethod()->isTracked(); - case static_cast<int>(Call::Role::SupportPresence): - return peerContactMethod()->supportPresence(); - case static_cast<int>(Call::Role::CategoryIcon): - return peerContactMethod()->category()->icon(peerContactMethod()->isTracked(),peerContactMethod()->isPresent()); - case static_cast<int>(Call::Role::CallCount): - return peerContactMethod()->callCount(); - case static_cast<int>(Call::Role::TotalSpentTime): - return peerContactMethod()->totalSpentTime(); - case static_cast<int>(Call::Role::Certificate): - return QVariant::fromValue(certificate()); - case static_cast<int>(Call::Role::HasAudioRecording): - return d_ptr->m_mRecordings[media::Media::Type::AUDIO][media::Media::Direction::IN]->size() > 0; - case static_cast<int>(Call::Role::HasVideoRecording): - return d_ptr->m_mRecordings[media::Media::Type::VIDEO][media::Media::Direction::IN]->size() > 0; - case static_cast<int>(Ring::Role::FormattedState): - case static_cast<int>(Call::Role::HumanStateName): - return toHumanStateName(state()); - case static_cast<int>(Call::Role::DropState): - return property("dropState"); - case static_cast<int>(Call::Role::Missed): - return isMissed(); - case static_cast<int>(Call::Role::LifeCycleState): - return QVariant::fromValue(lifeCycleState()); - case static_cast<int>(Call::Role::DTMFAnimState): - return property("DTMFAnimState"); - case static_cast<int>(Call::Role::LastDTMFidx): - return property("latestDtmfIdx"); - case static_cast<int>(Call::Role::DropPosition): - return property("dropPosition"); - case static_cast<int>(Call::Role::SecurityLevel): //TODO remove - return QVariant::fromValue(account()->securityEvaluationModel()->securityLevel()); - case static_cast<int>(Call::Role::SecurityLevelIcon): //TODO remove - return GlobalInstances::pixmapManipulator().securityLevelIcon(account()->securityEvaluationModel()->securityLevel()); - case static_cast<int>(Ring::Role::UnreadTextMessageCount): - return 0; - break; - default: - break; - }; - return QVariant(); -} - -void Call::playDTMF(const QString& str) -{ - Q_NOREPLY CallManager::instance().playDTMF(str); - emit dtmfPlayed(str); -} - -#undef Q_ASSERT_IS_IN_PROGRESS -#undef FORCE_ERROR_STATE -#undef FORCE_ERROR_STATE_P - -#include <call.moc> diff --git a/src/call.h b/src/call.h deleted file mode 100644 index fd3b35d14f08718c7948b625cc9f9736a98daf68..0000000000000000000000000000000000000000 --- a/src/call.h +++ /dev/null @@ -1,415 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <itembase.h> -#include <time.h> - -//Qt -#include <QtCore/QDebug> -class QString; -class QTimer; - -//Ring -#include "typedefs.h" -#include "media/media.h" -#include "itemdataroles.h" -class Account ; -class InstantMessagingModel ; -class ContactMethod ; -class TemporaryContactMethod; -class CollectionInterface ; -class Certificate ; -class Person ; - -namespace Video { - class Manager; - class Renderer; - class ManagerPrivate; -} - -namespace media { - class Media; - class Audio; - class Video; - class Text; - class Recording; -} - -class Call; - -//Private -class CallPrivate; - -namespace RingMimes -{ - QMimeData* payload(const Call*, const ContactMethod*, const Person*); -} - - -/** - * This class represent a call object from a client perspective. It is - * fully stateful and has all properties required for a client. This object - * is created by the CallModel class and its state can be modified by sending - * Call::Action to the call using the '<<' operator. - * - * History calls will have the Call::State::OVER set by default. The LifeCycleState - * system is designed to ensure that the call never go backward in its expected - * lifecycle and should be used instead of "if"/"switch" on individual states - * when possible. This will avoid accidentally forgetting a state. -**/ -class LIB_EXPORT Call : public ItemBase -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop -public: - friend class IMConversationManager; - friend class VideoRendererManager; - friend class VideoRendererManagerPrivate; - friend class media::Media; - friend class media::Audio; - friend class media::Video; - friend class media::Text; - friend class MediaTypeInference; - friend class IMConversationManagerPrivate; - friend QMimeData* RingMimes::payload(const Call*, const ContactMethod*, const Person*); - - //Enum - - ///Model roles - enum class Role { - Name = static_cast<int>(Ring::Role::UserRole) + 100, /*!< The peer name from SIP or Persons */ - Number , /*!< The peer URI / phone number (as text) */ - Direction , /*!< */ - Date , /*!< The date when the call started */ - Length , /*!< The current length of the call */ - FormattedDate , /*!< An human readable starting date */ - Historystate , /*!< */ - Filter , /*!< */ - FuzzyDate , /*!< */ - IsBookmark , /*!< */ - Security , /*!< */ - Department , /*!< */ - Email , /*!< */ - Organisation , /*!< */ - HasAVRecording , /*!< */ - Object , /*!< */ - Photo , /*!< */ - State , /*!< */ - StartTime , /*!< */ - StopTime , /*!< */ - IsAVRecording , /*!< */ - ContactMethod , /*!< */ - IsPresent , /*!< */ - SupportPresence , /*!< */ - IsTracked , /*!< */ - CategoryIcon , /*!< */ - CallCount , /*!< The number of calls made with the same phone number */ - TotalSpentTime , /*!< The total time spent speaking to with this phone number */ - Missed , /*!< This call has been missed */ - LifeCycleState , /*!< */ - Certificate , /*!< The certificate (for encrypted calls) */ - HasAudioRecording , /*!< */ - HasVideoRecording , /*!< */ - HumanStateName , /*!< */ - DTMFAnimState , /*!< GUI related state to hold animation key(s) */ - LastDTMFidx , /*!< The last DTMF (button) sent on this call */ - DropPosition , /*!< GUI related state to keep track of metadata during drag and drop */ - DateOnly , - DateTime , - SecurityLevel , //TODO REMOVE use the extensions - SecurityLevelIcon , //TODO REMOVE use the extensions - DropState = static_cast<int>(Ring::Role::DropState), /*!< GUI related state to keep track of metadata during drag and drop */ - }; - - enum DropAction { - Conference = 100, - Transfer = 101, - }; - - ///Possible call states - enum class State : unsigned int{ - #pragma push_macro("ERROR") - #undef ERROR - NEW = 0, /*!< The call has been created, but no dialing number been set */ - INCOMING = 1, /*!< Ringing incoming call */ - RINGING = 2, /*!< Ringing outgoing call */ - CURRENT = 3, /*!< Call to which the user can speak and hear */ - DIALING = 4, /*!< Call which numbers are being added by the user */ - HOLD = 5, /*!< Call is on hold by this side of the communication, @see Call::HoldFlags */ - FAILURE = 6, /*!< Call has failed */ - BUSY = 7, /*!< Call is busy */ - TRANSFERRED = 8, /*!< Call is being transferred. During this state, the user can enter the new number. */ - TRANSF_HOLD = 9, /*!< Call is on hold for transfer */ - OVER = 10,/*!< Call is over and should not be used */ - ERROR = 11,/*!< This state should never be reached */ - CONFERENCE = 12,/*!< This call is the current conference */ - CONFERENCE_HOLD = 13,/*!< This call is a conference on hold */ - INITIALIZATION = 14,/*!< The call have been placed, but the peer hasn't confirmed yet */ - ABORTED = 15,/*!< The call was dropped before being sent to the daemon */ - CONNECTED = 16,/*!< The peer has been found, attempting negotiation */ - COUNT__, - #pragma pop_macro("ERROR") - }; - Q_ENUMS(State) - - ///@enum Direction If the user have been called or have called - enum class Direction : int { - INCOMING, /*!< Someone has called */ - OUTGOING, /*!< The user called someone */ - }; - Q_ENUMS(Direction) - - ///Is the call between one or more participants - enum class Type { - CALL , /*!< A simple call */ - CONFERENCE, /*!< A composition of other calls */ - HISTORY , /*!< A call from a previous session */ - }; - - /** @enum Call::Action - * This enum have all the actions you can make on a call. - */ - enum class Action : unsigned int - { - ACCEPT = 0, /*!< Accept, create or place call or place transfer */ - REFUSE = 1, /*!< Red button, refuse or hang up */ - TRANSFER = 2, /*!< Put into or out of transfer mode */ - HOLD = 3, /*!< Hold or unhold the call */ - RECORD_AUDIO = 4, /*!< Enable or disable audio recording */ - RECORD_VIDEO = 5, /*!< Enable or disable video recording */ - RECORD_TEXT = 6, /*!< Enable or disable text recording */ - COUNT__, - }; - Q_ENUMS(Action) - - /** @enum Call::LifeCycleState - * This enum help track the call meta state - * @todo Eventually add a meta state between progress and finished for - * calls that are still relevant enough to be in the main UI, such - * as BUSY OR FAILURE while also finished - */ - enum class LifeCycleState { - CREATION = 0, /*!< Anything before creating the daemon call */ - INITIALIZATION = 1, /*!< Anything before the media transfer start */ - PROGRESS = 2, /*!< The peers are in communication (or hold) */ - FINISHED = 3, /*!< Everything is over, there is no going back */ - COUNT__ - }; - Q_ENUMS(LifeCycleState) - - /** @enum Call::HoldFlags - * Those flags help track the holding state of a call. Call::State::HOLD is - * only used for outgoing holding. - */ - enum class HoldFlags { - #pragma push_macro("OUT") - #pragma push_macro("IN") - #undef OUT - #undef IN - NONE = 0x0 << 0, /*!< The call is not on hold */ - OUT = 0x1 << 0, /*!< This side put the peer on hold */ - IN = 0x1 << 1, /*!< The peer put this side on hold */ - COUNT__ - #pragma pop_macro("OUT") - #pragma pop_macro("IN") - }; - Q_FLAGS(HoldFlags) - - ///TODO should be deprecated when a better factory system is implemented - class HistoryMapFields { - public: - constexpr static const char* ACCOUNT_ID = "accountid" ; - constexpr static const char* CALLID = "callid" ; - constexpr static const char* DISPLAY_NAME = "display_name" ; - constexpr static const char* PEER_NUMBER = "peer_number" ; - constexpr static const char* RECORDING_PATH = "recordfile" ; - constexpr static const char* STATE = "state" ; - constexpr static const char* TIMESTAMP_START = "timestamp_start"; - constexpr static const char* TIMESTAMP_STOP = "timestamp_stop" ; - constexpr static const char* MISSED = "missed" ; - constexpr static const char* DIRECTION = "direction" ; - constexpr static const char* CONTACT_USED = "contact_used" ; - constexpr static const char* CONTACT_UID = "contact_uid" ; - constexpr static const char* NUMBER_TYPE = "number_type" ; - constexpr static const char* CERT_PATH = "cert_path" ; - }; - - //TODO should be deprecated when a better factory system is implemented - ///@class HistoryStateName history map fields state names - class HistoryStateName { - public: - constexpr static const char* MISSED = "missed" ; - constexpr static const char* INCOMING = "incoming"; - constexpr static const char* OUTGOING = "outgoing"; - }; - - //Read only properties - Q_PROPERTY( Call::State state READ state NOTIFY stateChanged ) - Q_PROPERTY( QString historyId READ historyId ) - Q_PROPERTY( Account* account READ account ) - Q_PROPERTY( bool isHistory READ isHistory ) - Q_PROPERTY( uint stopTimeStamp READ stopTimeStamp ) - Q_PROPERTY( uint startTimeStamp READ startTimeStamp ) - Q_PROPERTY( bool isSecure READ isSecure ) - Q_PROPERTY( Video::Renderer* videoRenderer READ videoRenderer NOTIFY videoStarted ) - Q_PROPERTY( QString formattedName READ formattedName ) - Q_PROPERTY( QString length READ length ) - Q_PROPERTY( bool recordingAV READ isAVRecording ) - Q_PROPERTY( QString toHumanStateName READ toHumanStateName ) - Q_PROPERTY( bool missed READ isMissed ) - Q_PROPERTY( Direction direction READ direction ) - Q_PROPERTY( bool hasVideo READ hasVideo ) - Q_PROPERTY( Certificate* certificate READ certificate ) - Q_PROPERTY( bool hasParentCall READ hasParentCall ) - - //Read/write properties - Q_PROPERTY( ContactMethod* peerContactMethod READ peerContactMethod WRITE setPeerContactMethod) - Q_PROPERTY( QString peerName READ peerName WRITE setPeerName ) - Q_PROPERTY( QString transferNumber READ transferNumber WRITE setTransferNumber ) - Q_PROPERTY( QString dialNumber READ dialNumber WRITE setDialNumber NOTIFY dialNumberChanged(QString)) - - //Constructors & Destructors - static Call* buildHistoryCall (const QMap<QString,QString>& hc); - - //Static getters - static const QString toHumanStateName ( const Call::State ); - - //Getters - Call::State state () const; - const QString historyId () const; - ContactMethod* peerContactMethod() const; - const QString peerName () const; - bool isAVRecording () const; - Account* account () const; - bool isHistory () const; - time_t stopTimeStamp () const; - time_t startTimeStamp () const; - bool isSecure () const; - const QString transferNumber () const; - const QString dialNumber () const; - Video::Renderer* videoRenderer () const; - const QString formattedName () const; - QString length () const; - QString toHumanStateName () const; - bool isMissed () const; - Call::Direction direction () const; - bool hasVideo () const; - Call::LifeCycleState lifeCycleState () const; - Call::Type type () const; - bool hasRemote () const; - Certificate* certificate () const; - FlagPack<HoldFlags> holdFlags () const; - bool hasParentCall () const; - QDateTime dateTime () const; - QDate date () const; - - Q_INVOKABLE QVariant roleData (int role) const; - Q_INVOKABLE QVariant roleData (Role role) const; - Q_INVOKABLE QMimeData* mimePayload ( ) const; - - template<typename T> - T* firstMedia(media::Media::Direction direction) const; - QList<media::Recording*> recordings (media::Media::Type type, media::Media::Direction direction) const; - QList<media::Media*> media (media::Media::Type type, media::Media::Direction direction) const; - bool hasMedia (media::Media::Type type, media::Media::Direction direction) const; - bool hasRecording(media::Media::Type type, media::Media::Direction direction) const; - bool isRecording (media::Media::Type type, media::Media::Direction direction) const; - QList<media::Media*> allMedia ( ) const; - - //Automated function - Q_INVOKABLE Call::State performAction(Call::Action action); - - //Setters - void setTransferNumber ( const QString& number ); - void setDialNumber ( const QString& number ); - void setDialNumber ( const ContactMethod* number ); - void setPeerContactMethod( ContactMethod* cm ); - void setPeerName ( const QString& name ); - void setAccount ( Account* account ); - void setParentCall ( Call* call ); - - //Mutators - template<typename T> - T* addOutgoingMedia(bool useExisting = true); - Q_INVOKABLE void appendText(const QString& str); - void backspaceItemText(); - void reset(); - bool joinToParent(); - - //syntactic sugar - Call* operator<<( Call::Action& c); - -private: - Call(const QString& confId, const QString& account); - ~Call(); - explicit Call(Call::State startState, const QString& peerName = QString(), ContactMethod* number = nullptr, Account* account = nullptr); //TODO MOVE TO PRIVATE - - //Friend API - const QString dringId() const; - - CallPrivate* d_ptr; - Q_DECLARE_PRIVATE(Call) - -public Q_SLOTS: - void playDTMF(const QString& str); - -Q_SIGNALS: - ///Emitted when a call change (state or details) - void changed(); - ///Emitted when the call is over - void isOver(); - ///Notify that a DTMF have been played - void dtmfPlayed(const QString& str); - ///Notify of state change - void stateChanged(Call::State newState, Call::State previousState); - ///Notify that the lifeCycleStateChanged - void lifeCycleStateChanged(Call::LifeCycleState newState, Call::LifeCycleState previousState); - ///The call start timestamp changed, this usually indicate the call has started - void startTimeStampChanged(time_t newTimeStamp); - ///The dial number has changed - void dialNumberChanged(const QString& number); - ///Announce a new video renderer - void videoStarted(Video::Renderer* renderer); //TODO remove, use the media signals - ///Remove a new video renderer - void videoStopped(Video::Renderer* renderer); //TODO remove, use the media signals - ///Notify when a media is added - void mediaAdded(media::Media* media); - ///Notify when a media state change - void mediaStateChanged(media::Media* media, const media::Media::State s, const media::Media::State m); - ///The holding combination has changed - void holdFlagsChanged(const FlagPack<HoldFlags>& current, const FlagPack<HoldFlags>& previous); -}; - -Q_DECLARE_METATYPE(Call*) -Q_DECLARE_METATYPE(Call::State) -Q_DECLARE_METATYPE(Call::Type) -Q_DECLARE_METATYPE(Call::Action) -Q_DECLARE_METATYPE(Call::Direction) -Q_DECLARE_METATYPE(Call::LifeCycleState) - -DECLARE_ENUM_FLAGS(Call::HoldFlags) - -Call* operator<<(Call* c, Call::Action a); -QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::State& c ); -QDebug LIB_EXPORT operator<<(QDebug dbg, const Call::Action& c ); - -#include <call.hpp> diff --git a/src/call.hpp b/src/call.hpp deleted file mode 100644 index 08a049baecd2b5218f5401f5a8a592e56cd314b6..0000000000000000000000000000000000000000 --- a/src/call.hpp +++ /dev/null @@ -1,87 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -class LIB_EXPORT MediaTypeInference { -public: - static media::Media* safeMediaCreator(Call* c, media::Media::Type t, media::Media::Direction d); - - template<typename T> - static inline media::Media::Type getType() { - const int id = MediaTypeInference::getId<T>(); - return MediaTypeInference::typeMap(!MediaTypeInference::typeMap().contains(id))[id]; - } - - template<typename T> - static int getId() { - static int id = genId(); - return id; - } - static QHash<int, media::Media::Type>& typeMap(bool regen = false); -private: - static int genId(); -}; - -/** - * Perform a safe cast of the first media of "T" type - * @example Media::Audio* audio = call->firstMedia<media::Audio>(media::Media::Direction::OUT); - * @return nullptr if none, the media otherwise. - */ -template<typename T> -T* Call::firstMedia(media::Media::Direction direction) const -{ - const media::Media::Type t = MediaTypeInference::getType<T>(); - - QList<media::Media*> ms = media(t, direction); - - if (!ms.isEmpty()) { - media::Media* m = ms[0]; - Q_ASSERT(m->type() == t); - - return reinterpret_cast<T*>(m); - } - - return nullptr; -} - -template<typename T> -T* Call::addOutgoingMedia(bool useExisting) -{ - #pragma push_macro("OUT") - #undef OUT - T* existing = firstMedia<T>(media::Media::Direction::OUT); - if (useExisting && existing) - return existing; - - media::Media::Type t = MediaTypeInference::getType<T>(); - - return static_cast<T*>(MediaTypeInference::safeMediaCreator(this,t, media::Media::Direction::OUT)); - #pragma pop_macro("OUT") -} - -#ifdef _MSC_VER -#define __attribute__(A) /*do nothing*/ -#endif // _MSC_VER - -#define REGISTER_MEDIA() __attribute__ ((unused)) static auto forceType = [] {\ - QHash<int,::media::Media::Type>& sTypeMap = MediaTypeInference::typeMap(0);\ - sTypeMap[MediaTypeInference::getId<media::Audio>()] = ::media::Media::Type::AUDIO;\ - sTypeMap[MediaTypeInference::getId<media::Video>()] = ::media::Media::Type::VIDEO;\ - sTypeMap[MediaTypeInference::getId<media::Text >()] = ::media::Media::Type::TEXT ;\ - sTypeMap[MediaTypeInference::getId<media::File >()] = ::media::Media::Type::FILE ;\ - return 0;\ -}(); diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp index 283d54e33804afd14d2b36ac402053e2d9c97258..b65997b2421f178dbe9535be14cdb315b47e524e 100644 --- a/src/callbackshandler.cpp +++ b/src/callbackshandler.cpp @@ -26,12 +26,10 @@ #include "api/behaviorcontroller.h" // Lrc -#include "account.h" #include "dbus/callmanager.h" #include "dbus/configurationmanager.h" #include "dbus/presencemanager.h" #include "dbus/videomanager.h" -#include "namedirectory.h" // DRing #include <datatransfer_interface.h> diff --git a/src/callbackshandler.h b/src/callbackshandler.h index 31409cf187f9f078d2fd31113843781861a66852..bf096fc1744e3fee814d373fc39ad5c545d255ac 100644 --- a/src/callbackshandler.h +++ b/src/callbackshandler.h @@ -28,7 +28,6 @@ // Lrc #include "typedefs.h" -#include "namedirectory.h" #include "api/datatransfer.h" #include "qtwrapper/conversions_wrap.hpp" diff --git a/src/callmodel.cpp b/src/callmodel.cpp deleted file mode 100644 index 166a94b738216d9899a2fe41efe01c4b8f83b7e7..0000000000000000000000000000000000000000 --- a/src/callmodel.cpp +++ /dev/null @@ -1,1476 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "callmodel.h" - -//Std -#include <atomic> - -//Qt -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> -#include <QtCore/QMimeData> -#include <QtCore/QItemSelectionModel> - -//Ring library -#include "call.h" -#include "uri.h" -#include "phonedirectorymodel.h" -#include "contactmethod.h" -#include "accountmodel.h" -#include "availableaccountmodel.h" -#include "dbus/metatypes.h" -#include "dbus/callmanager.h" -#include "dbus/configurationmanager.h" -#include "dbus/instancemanager.h" -#include "private/videorenderermanager.h" -#include "private/imconversationmanagerprivate.h" -#include "mime.h" -#include "typedefs.h" -#include "collectioninterface.h" -#include "dbus/videomanager.h" -#include "categorizedhistorymodel.h" -#include "globalinstances.h" -#include "interfaces/contactmethodselectori.h" -#include "personmodel.h" -#include "video/renderer.h" -#include "media/audio.h" -#include "media/video.h" -#include "private/media_p.h" -#include "call_const.h" - -//System -#ifndef _MSC_VER -#include <unistd.h> -#else -#include "../../daemon/MSVC/unistd.h" -#endif // !_MSC_VER -#include <errno.h> - -//Private -#include "private/call_p.h" - -//Define -///InternalStruct: internal representation of a call -struct InternalStruct { - InternalStruct() : m_pParent(nullptr),call_real(nullptr),conference(false){} - Call* call_real ; - QModelIndex index ; - QList<InternalStruct*> m_lChildren; - bool conference ; - InternalStruct* m_pParent ; -}; - -class CallModelPrivate final : public QObject -{ - Q_OBJECT -public: - CallModelPrivate(CallModel* parent); - void init(); - Call* addCall2 ( Call* call , Call* parent = nullptr ); - Call* addConference ( const QString& confID ); - void removeConference ( const QString& confId ); - void removeCall ( Call* call , bool noEmit = false ); - Call* addIncomingCall ( const QString& callId ); - Call* addExistingCall ( const QString& callId, const QString& state); - - //Attributes - QList<InternalStruct*> m_lInternalModel; - QHash< Call* , InternalStruct* > m_shInternalMapping ; - QHash< QString , InternalStruct* > m_shDringId ; - QItemSelectionModel* m_pSelectionModel; - - //Helpers - bool isPartOf(const QModelIndex& confIdx, Call* call); - void removeConference ( Call* conf ); - void removeInternal(InternalStruct* internal); - static QStringList getCallList(); - - private: - CallModel* q_ptr; - - private Q_SLOTS: - void slotCallStateChanged ( const QString& callID , const QString &state, int code); - void slotIncomingCall ( const QString& accountID , const QString & callID ); - void slotIncomingConference ( const QString& confID ); - void slotChangingConference ( const QString& confID , const QString &state ); - void slotConferenceRemoved ( const QString& confId ); - void slotAddPrivateCall ( Call* call ); - void slotNewRecordingAvail ( const QString& callId , const QString& filePath); - void slotCallChanged ( ); - void slotStateChanged ( Call::State newState, Call::State previousState ); - void slotDialNumberChanged ( const QString& entry ); - void slotDTMFPlayed ( const QString& str ); - void slotRecordStateChanged ( const QString& callId , bool state ); - void slotAudioMuted ( const QString& callId , bool state ); - void slotVideoMutex ( const QString& callId , bool state ); - void slotPeerHold ( const QString& callId , bool state ); -}; - - -/***************************************************************************** - * * - * Constructor * - * * - ****************************************************************************/ - -///Singleton -CallModel& CallModel::instance() -{ - static auto instance = new CallModel(); - - // Fix loop-dependency issue between constructors - static std::atomic_flag init_flag {ATOMIC_FLAG_INIT}; - if (not init_flag.test_and_set()) - instance->d_ptr->init(); - - return *instance; -} - -CallModelPrivate::CallModelPrivate(CallModel* parent) : QObject(parent),q_ptr(parent),m_pSelectionModel(nullptr) -{ - -} - -///Retrieve current and older calls from the daemon, fill history, model and enable drag n' drop -CallModel::CallModel() : QAbstractItemModel(QCoreApplication::instance()),d_ptr(new CallModelPrivate(this)) -{ - //Register with the daemon - InstanceManager::instance(); - setObjectName("CallModel"); - #ifdef ENABLE_VIDEO - VideoRendererManager::instance(); - #endif - - //Necessary to receive text message - IMConversationManagerPrivate::instance(); -} //CallModel - -///Constructor (there fix an initializationn loop) -void CallModelPrivate::init() -{ - CallManagerInterface& callManager = CallManager::instance(); -#ifdef ENABLE_VIDEO - VideoManager::instance(); -#endif - - connect(&callManager, SIGNAL(callStateChanged(QString, QString, int)), this, SLOT(slotCallStateChanged(QString, QString, int)), Qt::QueuedConnection); - connect(&callManager, SIGNAL(recordingStateChanged(QString, bool)), this, SLOT(slotRecordStateChanged(QString, bool)), Qt::QueuedConnection); - - registerCommTypes(); - - const QStringList callList = getCallList(); - foreach (const QString& callId, callList) { - Call* tmpCall = CallPrivate::buildExistingCall(callId); - addCall2(tmpCall); - } - - const QStringList confList = callManager.getConferenceList(); - foreach (const QString& confId, confList) { - Call* conf = addConference(confId); - emit q_ptr->conferenceCreated(conf); - } -} - -///Destructor -CallModel::~CallModel() -{ - const QList<Call*> keys = d_ptr->m_shInternalMapping.keys(); - const QList<InternalStruct*> values = d_ptr->m_shInternalMapping.values(); - foreach (Call* call, keys ) - delete call; - foreach (InternalStruct* s, values ) - delete s; - d_ptr->m_shInternalMapping.clear (); - d_ptr->m_shDringId.clear(); - - //Unregister from the daemon - InstanceManagerInterface& instance = InstanceManager::instance(); - Q_NOREPLY instance.Unregister(getpid()); -#ifdef ENABLE_LIBWRAP - -#else - instance.connection().disconnectFromBus(instance.connection().baseService()); -#endif //ENABLE_LIBWRAP -} - -QHash<int,QByteArray> CallModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles.insert(static_cast<int>(Call::Role::Name ) ,QByteArray("name") ); - roles.insert(static_cast<int>(Call::Role::Number ) ,QByteArray("number") ); - roles.insert(static_cast<int>(Call::Role::Direction ) ,QByteArray("direction") ); - roles.insert(static_cast<int>(Call::Role::Date ) ,QByteArray("date") ); - roles.insert(static_cast<int>(Call::Role::Length ) ,QByteArray("length") ); - roles.insert(static_cast<int>(Call::Role::FormattedDate ) ,QByteArray("formattedDate") ); - roles.insert(static_cast<int>(Call::Role::HasAVRecording ) ,QByteArray("hasAVRecording") ); - roles.insert(static_cast<int>(Call::Role::Historystate ) ,QByteArray("historyState") ); - roles.insert(static_cast<int>(Call::Role::Filter ) ,QByteArray("filter") ); - roles.insert(static_cast<int>(Call::Role::FuzzyDate ) ,QByteArray("fuzzyDate") ); - roles.insert(static_cast<int>(Call::Role::IsBookmark ) ,QByteArray("isBookmark") ); - roles.insert(static_cast<int>(Call::Role::Security ) ,QByteArray("security") ); - roles.insert(static_cast<int>(Call::Role::Department ) ,QByteArray("department") ); - roles.insert(static_cast<int>(Call::Role::Email ) ,QByteArray("email") ); - roles.insert(static_cast<int>(Call::Role::Organisation ) ,QByteArray("organisation") ); - roles.insert(static_cast<int>(Call::Role::Object ) ,QByteArray("object") ); - roles.insert(static_cast<int>(Call::Role::Photo ) ,QByteArray("photo") ); - roles.insert(static_cast<int>(Call::Role::State ) ,QByteArray("state") ); - roles.insert(static_cast<int>(Call::Role::StartTime ) ,QByteArray("startTime") ); - roles.insert(static_cast<int>(Call::Role::StopTime ) ,QByteArray("stopTime") ); - roles.insert(static_cast<int>(Call::Role::DropState ) ,QByteArray("dropState") ); - roles.insert(static_cast<int>(Call::Role::DTMFAnimState ) ,QByteArray("dTMFAnimState") ); - roles.insert(static_cast<int>(Call::Role::LastDTMFidx ) ,QByteArray("lastDTMFidx") ); - roles.insert(static_cast<int>(Call::Role::IsAVRecording ) ,QByteArray("isAVRecording") ); - roles.insert(static_cast<int>(Call::Role::LifeCycleState ) ,QByteArray("lifeCycleState") ); - roles.insert(static_cast<int>(Call::Role::DateOnly ) ,QByteArray("dateOnly") ); - roles.insert(static_cast<int>(Call::Role::DateTime ) ,QByteArray("dateTime") ); - } - return roles; -} - -QItemSelectionModel* CallModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<CallModel*>(this)); - } - return d_ptr->m_pSelectionModel; -} - -/** - * Use the selection model to extract the current Call - * - * @return The selection call or nullptr - */ -Call* CallModel::selectedCall() const -{ - return getCall(selectionModel()->currentIndex()); -} - -/** - * Select a call or remove the selection if the call is invalid - * - * @param call the call to select - */ -void CallModel::selectCall(Call* call) const -{ - const QModelIndex idx = getIndex(call); - - selectionModel()->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); -} - -/** - * Select and return the dialing call. If there is none, one will be added - * - * @see CallModel::dialingCall - * @return the dialing call - */ -Call* CallModel::selectDialingCall(const QString& peerName, Account* account) -{ - Call* c = dialingCall(peerName,account); - - selectCall(c); - - return c; -} - -/***************************************************************************** - * * - * Access related functions * - * * - ****************************************************************************/ - -///Return the active call count -int CallModel::size() -{ - return d_ptr->m_lInternalModel.size(); -} - -///Return the action call list -CallList CallModel::getActiveCalls() -{ - CallList callList; - foreach(InternalStruct* internalS, d_ptr->m_lInternalModel) { - callList.push_back(internalS->call_real); - if (internalS->m_lChildren.size()) { - foreach(InternalStruct* childInt,internalS->m_lChildren) { - callList.push_back(childInt->call_real); - } - } - } - return callList; -} //getCallList - -///Return all conferences -CallList CallModel::getActiveConferences() -{ - CallList confList; - - //That way it can not be invalid - const QStringList confListS = CallManager::instance().getConferenceList(); - foreach (const QString& confId, confListS) { - InternalStruct* internalS = d_ptr->m_shDringId[confId]; - if (!internalS) { - qDebug() << "Warning: Conference not found, creating it, this should not happen"; - Call* conf = d_ptr->addConference(confId); - confList << conf; - emit conferenceCreated(conf); - } - else - confList << internalS->call_real; - } - return confList; -} //getConferenceList - -bool CallModel::hasConference() const -{ - foreach(const InternalStruct* s, d_ptr->m_lInternalModel) { - if (s->m_lChildren.size()) - return true; - } - return false; -} - -QList<Call*> CallModel::getConferenceParticipants(Call* conf) const -{ - QList<Call*> participantCallList; - - const auto internalConf = d_ptr->m_shInternalMapping[conf]; - foreach (const auto s, internalConf->m_lChildren) { - participantCallList << s->call_real; - } - return participantCallList; -} - -bool CallModel::isConnected() const -{ -#ifdef ENABLE_LIBWRAP - return InstanceManager::instance().isConnected(); -#else - return InstanceManager::instance().connection().isConnected(); -#endif //ENABLE_LIBWRAP -} - -bool CallModel::isValid() -{ - return CallManager::instance().isValid(); -} - -/***************************************************************************** - * * - * Call related code * - * * - ****************************************************************************/ - -///Get the call associated with this index -Call* CallModel::getCall( const QModelIndex& idx ) const -{ - if (idx.isValid() && idx.data(static_cast<int>(Call::Role::Object)).canConvert<Call*>()) - return qvariant_cast<Call*>(idx.data(static_cast<int>(Call::Role::Object))); - return nullptr; -} - -///Get the call associated with this ID -Call* CallModel::getCall( const QString& callId ) const -{ - if (d_ptr->m_shDringId.value(callId)) { - return d_ptr->m_shDringId[callId]->call_real; - } - return nullptr; -} - -///Make sure all signals can be mapped back to Call objects -void CallModel::registerCall(Call* call) -{ - d_ptr->m_shDringId[ call->dringId() ] = d_ptr->m_shInternalMapping[call]; -} - -///Add a call in the model structure, the call must exist before being added to the model -Call* CallModelPrivate::addCall2(Call* call, Call* parentCall) -{ - //The current History implementation doesn't support conference - //if something try to add an history conference, something went wrong - if (!call - || ((parentCall && parentCall->lifeCycleState() == Call::LifeCycleState::FINISHED) - && (call->lifeCycleState() == Call::LifeCycleState::FINISHED))) { - - qWarning() << "Trying to add an invalid call to the tree" << call; - Q_ASSERT(false); - - //WARNING this will trigger an assert later on, but isn't critical enough in release mode. - //HACK This return an invalid object that should be equivalent to NULL but won't require - //nullptr check everywhere in the code. It is safer to use an invalid object rather than - //causing a NULL dereference - return new Call(QString(),QString()); - } - if (m_shInternalMapping[call]) { - qWarning() << "Trying to add a call that already have been added" << call; - Q_ASSERT(false); - } - - //Even history call currently need to be tracked in CallModel, this may change - InternalStruct* aNewStruct = new InternalStruct; - aNewStruct->call_real = call; - aNewStruct->conference = false; - - m_shInternalMapping [ call ] = aNewStruct; - if (call->lifeCycleState() != Call::LifeCycleState::FINISHED) { - q_ptr->beginInsertRows(QModelIndex(),m_lInternalModel.size(),m_lInternalModel.size()); - m_lInternalModel << aNewStruct; - q_ptr->endInsertRows(); - } - - //Dialing calls don't have remote yet, it will be added later - if (call->hasRemote()) - m_shDringId[ call->dringId() ] = aNewStruct; - - //If the call is already finished, there is no point to track it here - if (call->lifeCycleState() != Call::LifeCycleState::FINISHED) { - emit q_ptr->callAdded(call,parentCall); - const QModelIndex idx = q_ptr->index(m_lInternalModel.size()-1,0,QModelIndex()); - emit q_ptr->dataChanged(idx, idx); - connect(call, &Call::changed, this, &CallModelPrivate::slotCallChanged); - connect(call,&Call::stateChanged,this,&CallModelPrivate::slotStateChanged); - connect(call,&Call::dialNumberChanged,this,&CallModelPrivate::slotDialNumberChanged); - connect(call,SIGNAL(dtmfPlayed(QString)),this,SLOT(slotDTMFPlayed(QString))); - connect(call,&Call::videoStarted,[this,call](Video::Renderer* r) { - emit q_ptr->rendererAdded(call, r); - }); - connect(call,&Call::videoStopped,[this,call](Video::Renderer* r) { - emit q_ptr->rendererRemoved(call, r); - }); - connect(call,&Call::mediaAdded, [this,call](media::Media* media) { - emit q_ptr->mediaAdded(call,media); - }); - connect(call,&Call::mediaStateChanged, [this,call](media::Media* media, const media::Media::State s, const media::Media::State m) { - emit q_ptr->mediaStateChanged(call,media,s,m); - }); - - foreach(auto m, call->allMedia()) - emit q_ptr->mediaAdded(call, m); - - emit q_ptr->layoutChanged(); - } - return call; -} //addCall - -///Return the current or create a new dialing call from peer ContactMethod -Call* CallModel::dialingCall(ContactMethod* cm, Call* parent) -{ - auto call = dialingCall(QString(), nullptr, parent); - call->setPeerContactMethod(cm); - return call; -} - -///Return the current or create a new dialing call from peer name and the account -Call* CallModel::dialingCall(const QString& peerName, Account* account, Call* parent) -{ - //Having multiple dialing calls could be supported, but for now we decided not to - //handle this corner case as it will create issues of its own - foreach (Call* call, getActiveCalls()) { - if (call->lifeCycleState() == Call::LifeCycleState::CREATION) - return call; - } - - return d_ptr->addCall2(CallPrivate::buildDialingCall(peerName, account, parent)); -} //dialingCall - -///Create a new incoming call when the daemon is being called -Call* CallModelPrivate::addIncomingCall(const QString& callId) -{ - qDebug() << "New incoming call:" << callId; - - // Since november 2015, calls are allowed to be declared with a state change - // if it has been done, then they should be ignored - // contains can be true and contain nullptr if it was accessed without - // contains() first - Call* call = nullptr; - if (not m_shDringId.value(callId)) { - - call = CallPrivate::buildIncomingCall(callId); - - //The call can already have been invalidated by the daemon, then do nothing - if (!call) - return nullptr; - - call = addCall2(call); - - //The call can already have been invalidated by the daemon, then do nothing - if (!call) - return nullptr; - - } else { - qDebug() << "The call" << callId << "already exist, avoiding re-creation"; - call = m_shDringId[callId]->call_real; - } - - //Call without account is not possible - if (call->account()) { - //WARNING: This code will need to be moved if we decide to drop - //incomingCall signal - if (call->account()->isAutoAnswer()) { - call->performAction(Call::Action::ACCEPT); - } - } - else { - qDebug() << "Incoming call from an invalid account"; - throw tr("Invalid account"); - } - return call; -} - -Call* CallModelPrivate::addExistingCall(const QString& callId, const QString& state) -{ - Q_UNUSED(state) - - qDebug() << "New foreign call:" << callId; - auto call = CallPrivate::buildExistingCall(callId); - - //The call can already have been invalidated by the daemon, then do nothing - if (!call) - return {}; - - call = addCall2(call); - - //The call can already have been invalidated by the daemon, then do nothing - if (!call) - return {}; - - //Call without account is not possible - if (not call->account()) { - qDebug() << "Foreign call from an invalid account"; - throw tr("Invalid account"); - } - - return call; -} - -///Properly remove an internal from the Qt model -void CallModelPrivate::removeInternal(InternalStruct* internal) -{ - if (!internal) return; - - const int idx = m_lInternalModel.indexOf(internal); - //Exit if the call is not found - if (idx == -1) { - qDebug() << "Cannot remove " << internal->call_real << ": call not found in tree"; - return; - } - - q_ptr->beginRemoveRows(QModelIndex(),idx,idx); - m_lInternalModel.removeAt(idx); - q_ptr->endRemoveRows(); -} - -/** - * LibRingClient doesn't [need to] handle INACTIVE calls - * This method make sure they never get into the system. - * - * It's not very efficient, but do the job. This method isn't - * called very often anyway. - */ -QStringList CallModelPrivate::getCallList() -{ - CallManagerInterface& callManager = CallManager::instance(); - const QStringList callList = callManager.getCallList(); - QStringList ret; - - for (const QString& callId : callList) { - QMap<QString, QString> details = callManager.getCallDetails(callId); - if (details[DRing::Call::Details::CALL_STATE] != DRing::Call::StateEvent::INACTIVE) - ret << callId; - } - - return ret; -} - -///Remove a call and update the internal structure -void CallModelPrivate::removeCall(Call* call, bool noEmit) -{ - Q_UNUSED(noEmit) - InternalStruct* internal = m_shInternalMapping[call]; - - if (!internal || !call) { - qDebug() << "Cannot remove " << (internal?internal->call_real:nullptr) << ": call not found"; - return; - } - - if (internal != nullptr) { - removeInternal(internal); - //NOTE Do not free the memory, it can still be used elsewhere or in modelindexes - } - - //Restore calls to the main list if they are not really over - if (internal->m_lChildren.size()) { - foreach(InternalStruct* child,internal->m_lChildren) { - if (child->call_real->state() != Call::State::OVER && child->call_real->state() != Call::State::ERROR) { - q_ptr->beginInsertRows(QModelIndex(),m_lInternalModel.size(),m_lInternalModel.size()); - m_lInternalModel << child; - q_ptr->endInsertRows(); - } - } - } - - //Be sure to reset these properties (just in case) - call->setProperty("DTMFAnimState",0); - call->setProperty("dropState",0); - - //The daemon often fail to emit the right signal, cleanup manually - foreach(InternalStruct* topLevel, m_lInternalModel) { - if (topLevel->call_real->type() == Call::Type::CONFERENCE && - (!topLevel->m_lChildren.size() - //HACK Make a simple validation to prevent ERROR->ERROR->ERROR state loop for conferences - || topLevel->m_lChildren.first()->call_real->state() == Call::State::ERROR - || topLevel->m_lChildren.last() ->call_real->state() == Call::State::ERROR)) - removeConference(topLevel->call_real); - } -// if (!noEmit) - emit q_ptr->layoutChanged(); -} //removeCall - - -QModelIndex CallModel::getIndex(Call* call) const -{ - if (!call) - return QModelIndex(); - - InternalStruct* internal = d_ptr->m_shInternalMapping[call]; - int idx = d_ptr->m_lInternalModel.indexOf(internal); - if (idx != -1) { - return index(idx,0); - } - else { - foreach(InternalStruct* str,d_ptr->m_lInternalModel) { - idx = str->m_lChildren.indexOf(internal); - if (idx != -1) - return index(idx,0,index(d_ptr->m_lInternalModel.indexOf(str),0)); - } - } - return QModelIndex(); -} - -///Transfer "toTransfer" to "target" and wait to see it it succeeded -void CallModel::attendedTransfer(Call* toTransfer, Call* target) -{ - if ((!toTransfer) || (!target)) return; - Q_NOREPLY CallManager::instance().attendedTransfer(toTransfer->dringId(),target->dringId()); - - //TODO [Daemon] Implement this correctly - toTransfer->d_ptr->changeCurrentState(Call::State::OVER); - target->d_ptr->changeCurrentState(Call::State::OVER); -} //attendedTransfer - -///Transfer this call to "target" number -void CallModel::transfer(Call* toTransfer, const ContactMethod* target) -{ - qDebug() << "Transferring call " << toTransfer << "to" << target->uri(); - toTransfer->setTransferNumber ( target->uri() ); - toTransfer->performAction ( Call::Action::TRANSFER ); - toTransfer->d_ptr->changeCurrentState( Call::State::TRANSFERRED ); - toTransfer->performAction ( Call::Action::ACCEPT ); - toTransfer->d_ptr->changeCurrentState( Call::State::OVER ); - emit toTransfer->isOver(); -} //transfer - -/***************************************************************************** - * * - * Conference related code * - * * - ****************************************************************************/ - -///Add a new conference, get the call list and update the interface as needed -Call* CallModelPrivate::addConference(const QString& confID) -{ - qDebug() << "Notified of a new conference " << confID; - CallManagerInterface& callManager = CallManager::instance(); - const QStringList callList = callManager.getParticipantList(confID); - qDebug() << "Paticiapants are:" << callList; - - if (!callList.size()) { - qDebug() << "This conference (" + confID + ") contain no call"; - return nullptr; - } - - if (!m_shDringId.value(callList[0])) { - qDebug() << "Invalid call"; - return nullptr; - } - - Call* newConf = nullptr; - if (m_shDringId[callList[0]]->call_real->account()) - newConf = new Call(confID, m_shDringId[callList[0]]->call_real->account()->id()); - - if (newConf) { - InternalStruct* aNewStruct = new InternalStruct; - aNewStruct->call_real = newConf; - aNewStruct->conference = true; - - m_shInternalMapping[newConf] = aNewStruct; - m_shDringId[confID] = aNewStruct; - q_ptr->beginInsertRows(QModelIndex(),m_lInternalModel.size(),m_lInternalModel.size()); - m_lInternalModel << aNewStruct; - q_ptr->endInsertRows(); - - foreach(const QString& callId,callList) { - InternalStruct* callInt = m_shDringId[callId]; - if (callInt) { - if (callInt->m_pParent && callInt->m_pParent != aNewStruct) - callInt->m_pParent->m_lChildren.removeAll(callInt); - removeInternal(callInt); - callInt->m_pParent = aNewStruct; - callInt->call_real->setProperty("dropState",0); - if (aNewStruct->m_lChildren.indexOf(callInt) == -1) { - auto parent = q_ptr->index(m_lInternalModel.indexOf(aNewStruct), 0, QModelIndex()); - q_ptr->beginInsertRows(parent, aNewStruct->m_lChildren.size(), aNewStruct->m_lChildren.size()); - aNewStruct->m_lChildren << callInt; - q_ptr->endInsertRows(); - } - } - else { - qDebug() << "References to unknown call"; - } - } - const QModelIndex idx = q_ptr->index(m_lInternalModel.size()-1,0,QModelIndex()); - emit q_ptr->dataChanged(idx, idx); - emit q_ptr->layoutChanged(); - connect(newConf, &Call::changed, this, &CallModelPrivate::slotCallChanged); - connect(newConf,&Call::videoStarted,[this,newConf](Video::Renderer* r) { - emit q_ptr->rendererAdded(newConf, r); - }); - connect(newConf,&Call::videoStopped,[this,newConf](Video::Renderer* r) { - emit q_ptr->rendererRemoved(newConf, r); - }); - } - - return newConf; -} //addConference - -bool CallModel::createJoinOrMergeConferenceFromCall(Call* call1, Call* call2) -{ - if (!call1 || !call2) return false; - qDebug() << "Joining call: " << call1 << " and " << call2; - if (call1->type() == Call::Type::CONFERENCE) - return addParticipant(call2, call1); - else if (call2->type() == Call::Type::CONFERENCE) - return addParticipant(call1, call2); - else if (call1->type() == Call::Type::CONFERENCE && call2->type() == Call::Type::CONFERENCE) - return mergeConferences(call1, call2); - else - Q_NOREPLY CallManager::instance().joinParticipant(call1->dringId(),call2->dringId()); - return true; -} //createConferenceFromCall - -///Add a new participant to a conference -bool CallModel::addParticipant(Call* call2, Call* conference) -{ - if (conference->type() == Call::Type::CONFERENCE) { - Q_NOREPLY CallManager::instance().addParticipant(call2->dringId(), conference->dringId()); - return true; - } - else { - qDebug() << "This is not a conference"; - return false; - } -} //addParticipant - -///Remove a participant from a conference -bool CallModel::detachParticipant(Call* call) -{ - Q_NOREPLY CallManager::instance().detachParticipant(call->dringId()); - return true; -} - -///Merge two conferences -bool CallModel::mergeConferences(Call* conf1, Call* conf2) -{ - Q_NOREPLY CallManager::instance().joinConference(conf1->dringId(),conf2->dringId()); - return true; -} - -///Remove a conference from the model and the TreeView -void CallModelPrivate::removeConference(const QString &confId) -{ - if (m_shDringId.value(confId)) - qDebug() << "Ending conversation containing " << m_shDringId[confId]->m_lChildren.size() << " participants"; - removeConference(q_ptr->getCall(confId)); -} - -///Remove a conference using it's call object -void CallModelPrivate::removeConference(Call* call) -{ - const InternalStruct* internal = m_shInternalMapping[call]; - - if (!internal) { - qDebug() << "Cannot remove conference: call not found"; - return; - } - removeCall(call,true); - - // currently the daemon does not emit a Call/Conference changed signal to indicate that the - // conference is over so we change the conf state here (since this is called when we get the - // "removeConference" signal from the daemon) - call->d_ptr->changeCurrentState(Call::State::OVER); -} - - -/***************************************************************************** - * * - * Model * - * * - ****************************************************************************/ - -///This model doesn't support direct write, only the dragState hack -bool CallModel::setData( const QModelIndex& idx, const QVariant &value, int role) -{ - if (idx.isValid()) { - if (role == static_cast<int>(Call::Role::DropState)) { - Call* call = getCall(idx); - if (call) - call->setProperty("dropState",value.toInt()); - emit dataChanged(idx,idx); - } - else if (role == Qt::EditRole) { - const QString number = value.toString(); - Call* call = getCall(idx); - if (call && number != call->dialNumber()) { - call->setDialNumber(number); - emit dataChanged(idx,idx); - return true; - } - } - else if (role == static_cast<int>(Call::Role::DTMFAnimState)) { - Call* call = getCall(idx); - if (call) { - call->setProperty("DTMFAnimState",value.toInt()); - emit dataChanged(idx,idx); - return true; - } - } - else if (role == static_cast<int>(Call::Role::DropPosition)) { - Call* call = getCall(idx); - if (call) { - call->setProperty("dropPosition",value.toInt()); - emit dataChanged(idx,idx); - return true; - } - } - } - return false; -} - -///Get information relative to the index -QVariant CallModel::data( const QModelIndex& idx, int role) const -{ - if (!idx.isValid()) - return QVariant(); - Call* call = nullptr; - if (!idx.parent().isValid() && d_ptr->m_lInternalModel.size() > idx.row() && d_ptr->m_lInternalModel[idx.row()]) - call = d_ptr->m_lInternalModel[idx.row()]->call_real; - else if (idx.parent().isValid() && d_ptr->m_lInternalModel.size() > idx.parent().row()) { - InternalStruct* intList = d_ptr->m_lInternalModel[idx.parent().row()]; - if (intList->conference == true && intList->m_lChildren.size() > idx.row() && intList->m_lChildren[idx.row()]) - call = intList->m_lChildren[idx.row()]->call_real; - } - return call?call->roleData((Call::Role)role):QVariant(); -} - -///Header data -QVariant CallModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(section) - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return QVariant(tr("Calls")); - return QVariant(); -} - -///The number of conference and stand alone calls -int CallModel::rowCount( const QModelIndex& parentIdx ) const -{ - if (!parentIdx.isValid() || !parentIdx.internalPointer()) - return d_ptr->m_lInternalModel.size(); - - const InternalStruct* modelItem = static_cast<InternalStruct*>(parentIdx.internalPointer()); - if (modelItem) { - if (modelItem->call_real->type() == Call::Type::CONFERENCE && modelItem->m_lChildren.size() > 0) - return modelItem->m_lChildren.size(); - else if (modelItem->call_real->type() == Call::Type::CONFERENCE) - qWarning() << modelItem->call_real << "have" - << modelItem->m_lChildren.size() << "and" - << ((modelItem->call_real->type() == Call::Type::CONFERENCE)?"is":"is not") << "a conference"; - } - return 0; -} - -///Make everything selectable and drag-able -Qt::ItemFlags CallModel::flags( const QModelIndex& idx ) const -{ - if (!idx.isValid()) - return Qt::NoItemFlags; - - const InternalStruct* modelItem = static_cast<InternalStruct*>(idx.internalPointer()); - if (modelItem ) { - const Call* c = modelItem->call_real; - return Qt::ItemIsEnabled|Qt::ItemIsSelectable - | Qt::ItemIsDragEnabled - | ((c->type() != Call::Type::CONFERENCE)?(Qt::ItemIsDropEnabled):Qt::ItemIsEnabled) - | ((c->lifeCycleState() == Call::LifeCycleState::CREATION)?Qt::ItemIsEditable:Qt::NoItemFlags); - } - return Qt::NoItemFlags; -} - -///Return valid payload types -int CallModel::acceptedPayloadTypes() -{ - return DropPayloadType::CALL | DropPayloadType::HISTORY | DropPayloadType::CONTACT | DropPayloadType::NUMBER | DropPayloadType::TEXT; -} - -///There is always 1 column -int CallModel::columnCount ( const QModelIndex& parentIdx) const -{ - const InternalStruct* modelItem = static_cast<InternalStruct*>(parentIdx.internalPointer()); - if (modelItem) { - return (modelItem->call_real->type() == Call::Type::CONFERENCE)?1:0; - } - else if (parentIdx.isValid()) - return 0; - return 1; -} - -///Return the conference if 'index' is part of one -QModelIndex CallModel::parent( const QModelIndex& idx) const -{ - if (!idx.isValid()) - return QModelIndex(); - const InternalStruct* modelItem = (InternalStruct*)idx.internalPointer(); - if (modelItem && modelItem->m_pParent) { - const int rowidx = d_ptr->m_lInternalModel.indexOf(modelItem->m_pParent); - if (rowidx != -1) { - return CallModel::index(rowidx,0,QModelIndex()); - } - } - return QModelIndex(); -} - -///Get the call index at row,column (active call only) -QModelIndex CallModel::index( int row, int column, const QModelIndex& parentIdx) const -{ - if (row >= 0 && !parentIdx.isValid() && d_ptr->m_lInternalModel.size() > row) - return createIndex(row,column,d_ptr->m_lInternalModel[row]); - - if (!parentIdx.isValid()) - return {}; - - if (row < 0 || parentIdx.row() >= d_ptr->m_lInternalModel.size()) - return {}; - - if (d_ptr->m_lInternalModel[parentIdx.row()]->m_lChildren.size() > row) - return createIndex(row,column,d_ptr->m_lInternalModel[parentIdx.row()]->m_lChildren[row]); - - return QModelIndex(); -} - -QStringList CallModel::mimeTypes() const -{ - static QStringList mimes; - if (!mimes.size()) { - mimes << RingMimes::PLAIN_TEXT << RingMimes::PHONENUMBER << RingMimes::CALLID << "text/html"; - } - return mimes; -} - -QMimeData* CallModel::mimeData(const QModelIndexList& indexes) const -{ - - if (indexes.size() == 1) { - const QModelIndex idx = indexes.first(); - if (idx.isValid()) { - Call* call = getCall(idx); - if (call) { - return call->mimePayload(); - } - } - } - - //TODO handle/hardcode something for multiple selections / composite MIME - - return new QMimeData(); -} - -bool CallModelPrivate::isPartOf(const QModelIndex& confIdx, Call* call) -{ - if (!confIdx.isValid() || !call) return false; - - for (int i=0;i<confIdx.model()->rowCount(confIdx);i++) { //TODO use model one directly - Call* c = q_ptr->getCall(confIdx); - if (c && c->dringId() == call->dringId()) { - return true; - } - } - return false; -} - -Call* CallModel::fromMime( const QByteArray& fromMime) const -{ - return getCall(QString(fromMime)); -} - -bool CallModel::dropMimeData(const QMimeData* mimedata, Qt::DropAction action, int row, int column, const QModelIndex& parentIdx ) -{ - Q_UNUSED(action) - const QModelIndex targetIdx = index( row,column,parentIdx ); - if (mimedata->hasFormat(RingMimes::CALLID)) { - const QByteArray encodedCallId = mimedata->data( RingMimes::CALLID ); - Call* call = fromMime ( encodedCallId ); - Call* target = getCall ( targetIdx ); - Call* targetParent = getCall ( targetIdx.parent() ); - - //Call or conference dropped on itself -> cannot transfer or merge, so exit now - if (target == call) { - qDebug() << "Call/Conf dropped on itself (doing nothing)"; - return false; - } - else if (!call) { - qDebug() << "Call not found"; - return false; - } - - switch (mimedata->property("dropAction").toInt()) { - case Call::DropAction::Conference: - //Call or conference dropped on part of itself -> cannot merge conference with itself - if (d_ptr->isPartOf(targetIdx,call) || d_ptr->isPartOf(targetIdx.parent(),call) || (call && targetParent && targetParent == call)) { - qDebug() << "Call/Conf dropped on its own conference (doing nothing)"; - return false; - } - //Conference dropped on a conference -> merge both conferences - else if (call && target && call->type() == Call::Type::CONFERENCE && target->type() == Call::Type::CONFERENCE) { - qDebug() << "Merge conferences" << call << "and" << target; - mergeConferences(call,target); - return true; - } - //Conference dropped on a call part of a conference -> merge both conferences - else if (call && call->type() == Call::Type::CONFERENCE && targetParent) { - qDebug() << "Merge conferences" << call << "and" << targetParent; - mergeConferences(call,getCall(targetIdx.parent())); - return true; - } - //Drop a call on a conference -> add it to the conference - else if (target && (targetIdx.parent().isValid() || target->type() == Call::Type::CONFERENCE)) { - Call* conf = target->type() == Call::Type::CONFERENCE?target:qvariant_cast<Call*>(targetIdx.parent().data(static_cast<int>(Call::Role::Object))); - if (conf) { - qDebug() << "Adding call " << call << "to conference" << conf; - addParticipant(call,conf); - return true; - } - } - //Conference dropped on a call - else if (target && call && rowCount(getIndex(call))) { - qDebug() << "Conference dropped on a call: adding call to conference"; - addParticipant(target,call); - return true; - } - //Call dropped on a call - else if (call && target && !targetIdx.parent().isValid()) { - qDebug() << "Call dropped on a call: creating a conference"; - createJoinOrMergeConferenceFromCall(call,target); - return true; - } - break; - case Call::DropAction::Transfer: - qDebug() << "Performing an attended transfer"; - attendedTransfer(call,target); - break; - default: - break; - } - } - else if (mimedata->hasFormat(RingMimes::PHONENUMBER)) { - const QByteArray encodedContactMethod = mimedata->data( RingMimes::PHONENUMBER ); - Call* target = getCall(targetIdx); - qDebug() << "Phone number" << encodedContactMethod << "on call" << target; - Call* newCall = dialingCall(QString(),target->account()); - ContactMethod* nb = PhoneDirectoryModel::instance().fromHash(encodedContactMethod); - newCall->setDialNumber(nb); - newCall->performAction(Call::Action::ACCEPT); - createJoinOrMergeConferenceFromCall(newCall,target); - } - else if (mimedata->hasFormat(RingMimes::CONTACT)) { - const QByteArray encodedPerson = mimedata->data(RingMimes::CONTACT); - Call* target = getCall(targetIdx); - qDebug() << "Contact" << encodedPerson << "on call" << target; - try { - const ContactMethod* number = GlobalInstances::contactMethodSelector().number( - PersonModel::instance().getPersonByUid(encodedPerson)); - if (!number->uri().isEmpty()) { - Call* newCall = dialingCall(); - newCall->setDialNumber(number); - newCall->performAction(Call::Action::ACCEPT); - createJoinOrMergeConferenceFromCall(newCall,target); - } - else { - qDebug() << "Person not found"; - } - } - catch (...) { - qDebug() << "There is nothing to handle contact"; - } - } - return false; -} - - -/***************************************************************************** - * * - * Slots * - * * - ****************************************************************************/ - -///When a call state change -void CallModelPrivate::slotCallStateChanged(const QString& callID, const QString& stateName, int code) -{ - - //This code is part of the CallModel interface too - qDebug() << "Call State Changed for call " << callID << " . New state : " << stateName; - InternalStruct* internal = m_shDringId[callID]; - Call* call = nullptr; - - if (!internal && stateName == DRing::Call::StateEvent::CONNECTING) - return; - - if(!internal) { - qDebug() << "Call not found" << callID << "new state" << stateName; - addExistingCall(callID, stateName); - return; - } else { - call = internal->call_real; - - QString sn = stateName; - - //Ring account handle "busy" differently from other types - if (call->account() - && call->account()->protocol() == Account::Protocol::RING - && sn == CallPrivate::StateChange::HUNG_UP - && code == ECONNREFUSED - ) - sn = CallPrivate::StateChange::BUSY; - - qDebug() << "Call found" << call << call->state(); - const Call::LifeCycleState oldLifeCycleState = call->lifeCycleState(); - const Call::State oldState = call->state(); - call->d_ptr->stateChanged(sn); - //Remove call when they end normally, keep errors and failure one - if ((sn == CallPrivate::StateChange::HUNG_UP) - || ((oldState == Call::State::OVER) && (call->state() == Call::State::OVER)) - || (oldLifeCycleState != Call::LifeCycleState::FINISHED && call->state() == Call::State::OVER)) { - removeCall(call); - } - } - - //Add to history - if (call->lifeCycleState() == Call::LifeCycleState::FINISHED) { - if (!call->collection()) { - foreach (CollectionInterface* backend, CategorizedHistoryModel::instance().collections(CollectionInterface::SupportedFeatures::ADD)) { - if (backend->editor<Call>()->addNew(call)) - call->setCollection(backend); - } - } - } - -} //slotCallStateChanged - -///When a new call is incoming -void CallModelPrivate::slotIncomingCall(const QString& accountID, const QString& callID) -{ - Q_UNUSED(accountID) - qDebug() << "Signal : Incoming Call ! ID = " << callID; - Call* c = addIncomingCall(callID); - - if (c) - emit q_ptr->incomingCall(c); -} - -///When a new conference is incoming -void CallModelPrivate::slotIncomingConference(const QString& confID) -{ - if (!q_ptr->getCall(confID)) { - Call* conf = addConference(confID); - qDebug() << "Adding conference" << conf << confID; - emit q_ptr->conferenceCreated(conf); - } -} - -///When a conference change -void CallModelPrivate::slotChangingConference(const QString &confID, const QString& state) -{ - InternalStruct* confInt = m_shDringId[confID]; - if (!confInt) { - qDebug() << "Error: conference not found"; - return; - } - Call* conf = confInt->call_real; - qDebug() << "Changing conference state" << conf << confID; - if (conf) { //Prevent a race condition between call and conference - if (!q_ptr->getIndex(conf).isValid()) { - qWarning() << "The conference item does not exist"; - return; - } - - conf->d_ptr->stateChanged(state); - CallManagerInterface& callManager = CallManager::instance(); - const QStringList participants = callManager.getParticipantList(confID); - - qDebug() << "The conf has" << confInt->m_lChildren.size() << "calls, daemon has" <<participants.size(); - - //First remove old participants, add them back to the top level list - foreach(InternalStruct* child,confInt->m_lChildren) { - if (participants.indexOf(child->call_real->dringId()) == -1 && child->call_real->lifeCycleState() != Call::LifeCycleState::FINISHED) { - qDebug() << "Remove" << child->call_real << "from" << conf; - child->m_pParent = nullptr; - q_ptr->beginInsertRows(QModelIndex(),m_lInternalModel.size(),m_lInternalModel.size()); - m_lInternalModel << child; - q_ptr->endInsertRows(); - } - } - - auto confIdx = q_ptr->index(m_lInternalModel.indexOf(confInt),0,QModelIndex()); - q_ptr->beginRemoveRows(confIdx,0,confInt->m_lChildren.size()); - confInt->m_lChildren.clear(); - q_ptr->endRemoveRows(); - - foreach(const QString& callId,participants) { - InternalStruct* callInt = m_shDringId[callId]; - if (callInt) { - if (callInt->m_pParent && callInt->m_pParent != confInt) - callInt->m_pParent->m_lChildren.removeAll(callInt); - removeInternal(callInt); - callInt->m_pParent = confInt; - q_ptr->beginInsertRows(confIdx, confInt->m_lChildren.size(), confInt->m_lChildren.size()); - confInt->m_lChildren << callInt; - q_ptr->endInsertRows(); - } - else { - qDebug() << "Participants not found"; - } - } - - //The daemon often fail to emit the right signal, cleanup manually - foreach(InternalStruct* topLevel, m_lInternalModel) { - if (topLevel->call_real->type() == Call::Type::CONFERENCE && !topLevel->m_lChildren.size()) { - removeConference(topLevel->call_real); - } - } - - //Test if there is no inconsistencies between the daemon and the client - const QStringList deamonCallList = getCallList(); - foreach(const QString& callId, deamonCallList) { - const QMap<QString,QString> callDetails = callManager.getCallDetails(callId); - InternalStruct* callInt = m_shDringId[callId]; - if (callInt) { - const QString confId = callDetails[DRing::Call::Details::CONF_ID]; - if (callInt->m_pParent) { - if (!confId.isEmpty() && callInt->m_pParent->call_real->dringId() != confId) { - qWarning() << "Conference parent mismatch"; - } - else if (confId.isEmpty() ){ - qWarning() << "Call:" << callId << "should not be part of a conference"; - callInt->m_pParent = nullptr; - } - } - else if (!confId.isEmpty()) { - qWarning() << "Found an orphan call"; - InternalStruct* confInt2 = m_shDringId[confId]; - if (confInt2 && confInt2->call_real->type() == Call::Type::CONFERENCE - && (callInt->call_real->type() != Call::Type::CONFERENCE)) { - removeInternal(callInt); - if (confInt2->m_lChildren.indexOf(callInt) == -1) { - auto confIdx2 = q_ptr->index(m_lInternalModel.indexOf(confInt2), 0, QModelIndex()); - q_ptr->beginInsertRows(confIdx2, confInt2->m_lChildren.size(), confInt2->m_lChildren.size()); - confInt2->m_lChildren << callInt; - q_ptr->endInsertRows(); - } - } - } - callInt->call_real->setProperty("dropState",0); - } - else - qWarning() << "Conference: Call from call list not found in internal list"; - } - - //TODO force reload all conferences too - - emit q_ptr->layoutChanged(); - emit q_ptr->dataChanged(confIdx, confIdx); - emit q_ptr->conferenceChanged(conf); - } - else { - qDebug() << "Trying to affect a conference that does not exist (anymore)"; - } -} //slotChangingConference - -///When a conference is removed -void CallModelPrivate::slotConferenceRemoved(const QString &confId) -{ - Call* conf = q_ptr->getCall(confId); - removeConference(confId); - emit q_ptr->layoutChanged(); - emit q_ptr->conferenceRemoved(conf); -} - -///Make the call aware it has a recording -void CallModelPrivate::slotNewRecordingAvail( const QString& callId, const QString& filePath) -{ - Call* c = q_ptr->getCall(callId); - if (c) - c->d_ptr->setRecordingPath(filePath); -} - -void CallModelPrivate::slotStateChanged(Call::State newState, Call::State previousState) -{ - Q_UNUSED(newState) - - Call* call = qobject_cast<Call*>(sender()); - if (call) - emit q_ptr->callStateChanged(call, previousState); -} - -/// Forward the Call::dialNumberChanged signal -void CallModelPrivate::slotDialNumberChanged(const QString& entry) -{ - if (Call* call = qobject_cast<Call*>(sender())) - emit q_ptr->dialNumberChanged(call, entry); -} - -///Update model if the data change -void CallModelPrivate::slotCallChanged() -{ - auto call = qobject_cast<Call*>(sender()); - if (!call) return; - - switch(call->state()) { - //Transfer is "local" state, it doesn't require the daemon, so it need to be - //handled "manually" instead of relying on the backend signals - case Call::State::TRANSFERRED: - emit q_ptr->callStateChanged(call, Call::State::TRANSFERRED); - break; - //Same goes for some errors - case Call::State::COUNT__: - case Call::State::ERROR: - removeCall(call); - break; - //Over can be caused by local events - case Call::State::ABORTED: - case Call::State::OVER: - removeCall(call); - break; - //Let the daemon handle the others - case Call::State::INCOMING: - case Call::State::RINGING: - case Call::State::INITIALIZATION: - case Call::State::CONNECTED: - case Call::State::CURRENT: - case Call::State::DIALING: - case Call::State::NEW: - case Call::State::HOLD: - case Call::State::FAILURE: - case Call::State::BUSY: - case Call::State::TRANSF_HOLD: - case Call::State::CONFERENCE: - case Call::State::CONFERENCE_HOLD: - break; - }; - - const QModelIndex idx = q_ptr->getIndex(call); - emit q_ptr->dataChanged(idx,idx); -} - -///Add call slot -void CallModelPrivate::slotAddPrivateCall(Call* call) { - if (m_shInternalMapping[call]) - return; - addCall2(call,nullptr); -} - -///Notice views that a dtmf have been played -void CallModelPrivate::slotDTMFPlayed( const QString& str ) -{ - Call* call = qobject_cast<Call*>(QObject::sender()); - if (str.size()==1) { - int idx = 0; - char s = str.toLower().toLatin1()[0]; - if (s >= '1' && s <= '9' ) idx = s - '1' ; - else if (s >= 'a' && s <= 'v') idx = (s - 'a')/3 ; - else if (s >= 'w' && s <= 'z') idx = 8 ; - else if (s == '0' ) idx = 10 ; - else if (s == '*' ) idx = 9 ; - else if (s == '#' ) idx = 11 ; - else idx = -1 ; - call->setProperty("latestDtmfIdx",idx); - } - const QModelIndex& idx = q_ptr->getIndex(call); - q_ptr->setData(idx,50, static_cast<int>(Call::Role::DTMFAnimState)); -} - -///Called when a recording state change -void CallModelPrivate::slotRecordStateChanged (const QString& callId, bool state) -{ - if (auto call = q_ptr->getCall(callId)) { - - call->d_ptr->m_mIsRecording[ media::Media::Type::AUDIO ].setAt( media::Media::Direction::IN , state); - call->d_ptr->m_mIsRecording[ media::Media::Type::AUDIO ].setAt( media::Media::Direction::OUT , state); - call->d_ptr->m_mIsRecording[ media::Media::Type::VIDEO ].setAt( media::Media::Direction::IN , state); - call->d_ptr->m_mIsRecording[ media::Media::Type::VIDEO ].setAt( media::Media::Direction::OUT , state); - - emit call->changed(); - } -} - -void CallModelPrivate::slotAudioMuted( const QString& callId, bool state) -{ - Call* call = q_ptr->getCall(callId); - - if (call) { - auto a = call->firstMedia<media::Audio>(media::Media::Direction::OUT); - if (state) - a->media::Media::d_ptr->muteConfirmed(); - else - a->media::Media::d_ptr->unmuteConfirmed(); - } -} - -void CallModelPrivate::slotVideoMutex( const QString& callId, bool state) -{ - Call* call = q_ptr->getCall(callId); - - if (call) { - auto v = call->firstMedia<media::Video>(media::Media::Direction::OUT); - if (state) - v->media::Media::d_ptr->muteConfirmed(); - else - v->media::Media::d_ptr->unmuteConfirmed(); - } -} - -void CallModelPrivate::slotPeerHold( const QString& callId, bool state) -{ - Call* call = q_ptr->getCall(callId); - - if (call) - call->d_ptr->peerHoldChanged(state); -} - -#include <callmodel.moc> diff --git a/src/callmodel.h b/src/callmodel.h deleted file mode 100644 index eb5fce23b08a9cef264f8bac4a96fcbd4bc2bab8..0000000000000000000000000000000000000000 --- a/src/callmodel.h +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QAbstractItemModel> -#include <QMap> -#include "typedefs.h" - -//Qt -class QItemSelectionModel; - -//Ring -#include "call.h" -class Account; -struct InternalStruct; -class ContactMethod; -class CallModelPrivate; -class CallPrivate; - -namespace Video { - class ManagerPrivate; - class Renderer; -} - -//Typedef -typedef QMap<uint, Call*> CallMap; -typedef QList<Call*> CallList; - -///CallModel: Central model/frontend to deal with dring -class LIB_EXPORT CallModel : public QAbstractItemModel -{ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" -Q_OBJECT -#pragma GCC diagnostic pop - - //Handling "in call" text message has been delayed to it's own manager - friend class IMConversationManagerPrivate; - //Now that the ID is set at a later time, this model need to be notified - friend class CallPrivate; - //The renderer use DringId as identifiers and have to be matched to calls - friend class VideoRendererManagerPrivate; - -public: - ///Accepted (mime) payload types - enum DropPayloadType { - NONE = 0 , /*!< No drop payload is supported */ - CALL = 1<<0, /*!< The item support the dropping of a current or history call */ - HISTORY = 1<<1, /*!< The item support the dropping of a history call */ - CONTACT = 1<<2, /*!< The item support the dropping of a contact id */ - NUMBER = 1<<3, /*!< The item support the dropping of an URI */ - TEXT = 1<<4, /*!< The item support the dropping of random text (to be interpreted as URI) */ - ACCOUNT = 1<<5, /*!< The item support the dropping of an account id */ - AUDIO_CODEC = 1<<6, /*!< The item support the dropping of an audio codec id */ - VIDEO_CODEC = 1<<7, /*!< The item support the dropping of a video codec id */ - }; - - //Properties - Q_PROPERTY(int size READ size ) - Q_PROPERTY(int callCount READ rowCount ) - Q_PROPERTY(bool isValid READ isValid ) - Q_PROPERTY(bool hasConference READ hasConference ) - Q_PROPERTY(bool isConnected READ isConnected ) - Q_PROPERTY(Call* selectedCall READ selectedCall ) - - //Call related - Q_INVOKABLE Call* dialingCall ( const QString& peerName=QString(), Account* account=nullptr, Call* parent = nullptr ); - Q_INVOKABLE Call* dialingCall (ContactMethod* cm , Call* parent = nullptr); - Q_INVOKABLE void attendedTransfer ( Call* toTransfer , Call* target ); - Q_INVOKABLE void transfer ( Call* toTransfer , const ContactMethod* target ); - Q_INVOKABLE QModelIndex getIndex ( Call* call ) const; - Q_INVOKABLE Call* fromMime ( const QByteArray& fromMime ) const; - Q_INVOKABLE Call* selectedCall ( ) const; - Q_INVOKABLE void selectCall ( Call* call ) const; - Q_INVOKABLE Call* selectDialingCall ( const QString& peerName=QString(), Account* account=nullptr ); - - //Conference related - Q_INVOKABLE bool createJoinOrMergeConferenceFromCall ( Call* call1, Call* call2 ); - Q_INVOKABLE bool mergeConferences ( Call* conf1, Call* conf2 ); - Q_INVOKABLE bool addParticipant ( Call* call2, Call* conference ); - Q_INVOKABLE bool detachParticipant ( Call* call ); - - //Getters - Q_INVOKABLE CallList getActiveCalls (); - Q_INVOKABLE CallList getActiveConferences(); - Q_INVOKABLE int acceptedPayloadTypes(); - bool isValid (); - int size (); - bool hasConference () const; - bool isConnected () const; - Q_INVOKABLE QItemSelectionModel* selectionModel() const; - - Q_INVOKABLE Call* getCall ( const QModelIndex& idx ) const; - Q_INVOKABLE QList<Call*> getConferenceParticipants(Call *conf) const; - - //Model implementation - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - virtual QStringList mimeTypes ( ) const override; - virtual QMimeData* mimeData ( const QModelIndexList &indexes ) const override; - virtual bool dropMimeData ( const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent ) override; - virtual QHash<int,QByteArray> roleNames() const override; - - - //Singleton - static CallModel& instance(); - virtual ~CallModel( ); - -private: - //Constructors, initializer and destructors - explicit CallModel(); - QScopedPointer<CallModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(CallModel) - - //Friend API - Call* getCall ( const QString& callId ) const; - void registerCall(Call* call); - -Q_SIGNALS: - ///Emitted when a call state change - void callStateChanged ( Call* call, Call::State previousState ); - ///Emitted when a new call is incoming - void incomingCall ( Call* call ); - ///Emitted when a conference is created - void conferenceCreated ( Call* conf ); - ///Emitted when a conference change state or participant - void conferenceChanged ( Call* conf ); - ///Emitted when a conference is removed - void conferenceRemoved ( Call* conf ); - ///Emitted when a call is added - void callAdded ( Call* call , Call* parent ); - ///Emitted when a new Video::Renderer is available - void rendererAdded ( Call* call, Video::Renderer* renderer ); - ///Emitted when a new Video::Renderer is removed - void rendererRemoved ( Call* call, Video::Renderer* renderer ); - ///Notify when a media is added - void mediaAdded ( Call* call, media::Media* media ); - ///Notify when the dial (search) field changed - void dialNumberChanged ( Call* call, const QString& entry ); - ///Notify when a media state change - void mediaStateChanged( Call* call, media::Media* media, const media::Media::State s, const media::Media::State m); -}; -Q_DECLARE_METATYPE(CallModel*) diff --git a/src/certificate.cpp b/src/certificate.cpp deleted file mode 100644 index 28e56713a3de6d31510c3f0a82dc1ca3db6fe35d..0000000000000000000000000000000000000000 --- a/src/certificate.cpp +++ /dev/null @@ -1,914 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "certificate.h" - -//Qt -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QDateTime> - -//STD -#include <stdint.h> - -//Ring daemon -#include <security_const.h> - -//Ring -#include "dbus/configurationmanager.h" -#include <certificatemodel.h> -#include "private/matrixutils.h" -#include "private/certificatemodel_p.h" -#include "private/certificate_p.h" -#include <account.h> -#include <chainoftrustmodel.h> -#include "contactmethod.h" - -Matrix1D<Certificate::Checks ,QString> CertificatePrivate::m_slChecksName = {{ - /* HAS_PRIVATE_KEY */ QObject::tr("Has a private key" ), - /* EXPIRED */ QObject::tr("Is not expired" ), - /* STRONG_SIGNING */ QObject::tr("Has strong signing" ), - /* NOT_SELF_SIGNED */ QObject::tr("Is not self signed" ), - /* KEY_MATCH */ QObject::tr("Have a matching key pair" ), - /* PRIVATE_KEY_STORAGE_PERMISSION */ QObject::tr("Has the right private key file permissions" ), - /* PUBLIC_KEY_STORAGE_PERMISSION */ QObject::tr("Has the right public key file permissions" ), - /* PRIVATE_KEY_DIRECTORY_PERMISSIONS */ QObject::tr("Has the right private key directory permissions" ), - /* PUBLIC_KEY_STORAGE_PERMISSION */ QObject::tr("Has the right public key directory permissions" ), - /* PRIVATE_KEY_STORAGE_LOCATION */ QObject::tr("Has the right private key directory location" ), - /* PUBLIC_KEY_STORAGE_LOCATION */ QObject::tr("Has the right public key directory location" ), - /* PRIVATE_KEY_SELINUX_ATTRIBUTES */ QObject::tr("Has the right private key SELinux attributes" ), - /* PUBLIC_KEY_SELINUX_ATTRIBUTES */ QObject::tr("Has the right public key SELinux attributes" ), - /* EXIST */ QObject::tr("The certificate file exist and is readable" ), - /* VALID */ QObject::tr("The file is a valid certificate" ), - /* VALID_AUTHORITY */ QObject::tr("The certificate has a valid authority" ), - /* KNOWN_AUTHORITY */ QObject::tr("The certificate has a known authority" ), - /* NOT_REVOKED */ QObject::tr("The certificate is not revoked" ), - /* AUTHORITY_MATCH */ QObject::tr("The certificate authority match" ), - /* EXPECTED_OWNER */ QObject::tr("The certificate has the expected owner" ), - /* ACTIVATED */ QObject::tr("The certificate is within its active period" ), -}}; - -Matrix1D<Certificate::Checks ,QString> CertificatePrivate::m_slChecksDescription = {{ - /* HAS_PRIVATE_KEY */ "TODO", - /* EXPIRED */ "TODO", - /* STRONG_SIGNING */ "TODO", - /* NOT_SELF_SIGNED */ "TODO", - /* KEY_MATCH */ "TODO", - /* PRIVATE_KEY_STORAGE_PERMISSION */ "TODO", - /* PUBLIC_KEY_STORAGE_PERMISSION */ "TODO", - /* PRIVATE_KEY_DIRECTORY_PERMISSIONS */ "TODO", - /* PUBLIC_KEY_DIRECTORY_PERMISSIONS */ "TODO", - /* PRIVATE_KEY_STORAGE_LOCATION */ "TODO", - /* PUBLIC_KEY_STORAGE_LOCATION */ "TODO", - /* PRIVATE_KEY_SELINUX_ATTRIBUTES */ "TODO", - /* PUBLIC_KEY_SELINUX_ATTRIBUTES */ "TODO", - /* EXIST */ "TODO", - /* VALID */ "TODO", - /* VALID_AUTHORITY */ "TODO", - /* KNOWN_AUTHORITY */ "TODO", - /* NOT_REVOKED */ "TODO", - /* AUTHORITY_MATCH */ "TODO", - /* EXPECTED_OWNER */ "TODO", - /* ACTIVATED */ "TODO", -}}; - -Matrix1D<Certificate::Details,QString> CertificatePrivate::m_slDetailssName = {{ - /* EXPIRATION_DATE */ QObject::tr("Expiration date" ), - /* ACTIVATION_DATE */ QObject::tr("Activation date" ), - /* REQUIRE_PRIVATE_KEY_PASSWORD */ QObject::tr("Require a private key password"), - /* PUBLIC_SIGNATURE */ QObject::tr("Public signature" ), - /* VERSION_NUMBER */ QObject::tr("Version" ), - /* SERIAL_NUMBER */ QObject::tr("Serial number" ), - /* ISSUER */ QObject::tr("Issuer" ), - /* SUBJECT_KEY_ALGORITHM */ QObject::tr("Subject key algorithm" ), - /* CN */ QObject::tr("Common name (CN)" ), - /* N */ QObject::tr("Name (N)" ), - /* O */ QObject::tr("Organization (O)" ), - /* SIGNATURE_ALGORITHM */ QObject::tr("Signature algorithm" ), - /* MD5_FINGERPRINT */ QObject::tr("Md5 fingerprint" ), - /* SHA1_FINGERPRINT */ QObject::tr("Sha1 fingerprint" ), - /* PUBLIC_KEY_ID */ QObject::tr("Public key ID" ), - /* ISSUER_DN */ QObject::tr("Issuer domain name" ), - /* NEXT_EXPECTED_UPDATE_DATE */ QObject::tr("Next expected update" ), - /* OUTGOING_SERVER */ QObject::tr("Outgoing server" ), - -}}; - -Matrix1D<Certificate::Details,QString> CertificatePrivate::m_slDetailssDescription = {{ - /* EXPIRATION_DATE */ "TODO", - /* ACTIVATION_DATE */ "TODO", - /* REQUIRE_PRIVATE_KEY_PASSWORD */ "TODO", - /* PUBLIC_SIGNATURE */ "TODO", - /* VERSION_NUMBER */ "TODO", - /* SERIAL_NUMBER */ "TODO", - /* ISSUER */ "TODO", - /* SUBJECT_KEY_ALGORITHM */ "TODO", - /* CN */ "TODO", - /* N */ "TODO", - /* O */ "TODO", - /* SIGNATURE_ALGORITHM */ "TODO", - /* MD5_FINGERPRINT */ "TODO", - /* SHA1_FINGERPRINT */ "TODO", - /* PUBLIC_KEY_ID */ "TODO", - /* ISSUER_DN */ "TODO", - /* NEXT_EXPECTED_UPDATE_DATE */ "TODO", - /* OUTGOING_SERVER */ "TODO", - -}}; - - -CertificatePrivate::CertificatePrivate(Certificate* p, LoadingType _type) : -q_ptr(p), m_pCheckCache(nullptr), m_pDetailsCache(nullptr), m_LoadingType(_type), -m_Statuses{0,0,0},m_RequirePrivateKey(false),m_RequireStrictPermissions(true), -m_pSignedBy(nullptr),m_pChainOfTrust(nullptr),m_pSeverityProxy(nullptr), -m_pContactMethod(nullptr) -{ -} - -CertificatePrivate::~CertificatePrivate() -{ - if (m_pDetailsCache ) delete m_pDetailsCache ; - if (m_pCheckCache ) delete m_pCheckCache ; - if (m_pSeverityProxy) delete m_pSeverityProxy; -} - -Certificate::CheckValues CertificatePrivate::toBool(const QString& string) -{ - if (string == DRing::Certificate::CheckValuesNames::PASSED) - return Certificate::CheckValues::PASSED; - else if (string == DRing::Certificate::CheckValuesNames::FAILED) - return Certificate::CheckValues::FAILED; - else - return Certificate::CheckValues::UNSUPPORTED; -} - -DetailsCache::DetailsCache(const MapStringString& details) -{ - m_ExpirationDate = QDateTime::fromString( details[DRing::Certificate::DetailsNames::EXPIRATION_DATE ],"yyyy-mm-dd"); - m_ActivationDate = QDateTime::fromString( details[DRing::Certificate::DetailsNames::ACTIVATION_DATE ],"yyyy-mm-dd"); - m_RequirePrivateKeyPassword = details[DRing::Certificate::DetailsNames::REQUIRE_PRIVATE_KEY_PASSWORD] == "PASSED"; - m_PublicSignature = details[DRing::Certificate::DetailsNames::PUBLIC_SIGNATURE ].toLatin1(); - m_VersionNumber = details[DRing::Certificate::DetailsNames::VERSION_NUMBER ].toInt(); - m_SerialNumber = details[DRing::Certificate::DetailsNames::SERIAL_NUMBER ].toLatin1(); - m_Issuer = details[DRing::Certificate::DetailsNames::ISSUER ]; - m_SubjectKeyAlgorithm = details[DRing::Certificate::DetailsNames::SUBJECT_KEY_ALGORITHM ].toLatin1(); - m_Cn = details[DRing::Certificate::DetailsNames::CN ]; - m_N = details[DRing::Certificate::DetailsNames::N ]; - m_O = details[DRing::Certificate::DetailsNames::O ]; - m_SignatureAlgorithm = details[DRing::Certificate::DetailsNames::SIGNATURE_ALGORITHM ].toLatin1(); - m_Md5Fingerprint = details[DRing::Certificate::DetailsNames::MD5_FINGERPRINT ].toLatin1(); - m_Sha1Fingerprint = details[DRing::Certificate::DetailsNames::SHA1_FINGERPRINT ].toLatin1(); - m_PublicKeyId = details[DRing::Certificate::DetailsNames::PUBLIC_KEY_ID ].toLatin1(); - m_IssuerDn = details[DRing::Certificate::DetailsNames::ISSUER_DN ].toLatin1(); - m_NextExpectedUpdateDate = QDateTime::fromString(details[DRing::Certificate::DetailsNames::NEXT_EXPECTED_UPDATE_DATE ],"yyyy-mm-dd"); - m_OutgoingServer = details[DRing::Certificate::DetailsNames::OUTGOING_SERVER ] ; -} - -ChecksCache::ChecksCache(const MapStringString& checks) -{ - m_HasPrivateKey = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::HAS_PRIVATE_KEY ]); - m_IsExpired = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::EXPIRED ]); - m_HasStrongSigning = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::STRONG_SIGNING ]); - m_IsSelfSigned = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::NOT_SELF_SIGNED ]); - m_PrivateKeyMatch = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::KEY_MATCH ]); - m_ArePrivateKeyStoragePermissionOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PRIVATE_KEY_STORAGE_PERMISSION ]); - m_ArePublicKeyStoragePermissionOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PUBLIC_KEY_STORAGE_PERMISSION ]); - m_ArePrivateKeyDirectoryPermissionsOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PRIVATE_KEY_DIRECTORY_PERMISSIONS]); - m_ArePublicKeyDirectoryPermissionsOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PUBLIC_KEY_DIRECTORY_PERMISSIONS ]); - m_ArePrivateKeyStorageLocationOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PRIVATE_KEY_STORAGE_LOCATION ]); - m_ArePublicKeyStorageLocationOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PUBLIC_KEY_STORAGE_LOCATION ]); - m_ArePrivateKeySelinuxAttributesOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PRIVATE_KEY_SELINUX_ATTRIBUTES ]); - m_ArePublicKeySelinuxAttributesOk = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::PUBLIC_KEY_SELINUX_ATTRIBUTES ]); - m_Exist = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::EXIST ]); - m_IsValid = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::VALID ]); - m_ValidAuthority = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::VALID_AUTHORITY ]); - m_HasKnownAuthority = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::KNOWN_AUTHORITY ]); - m_IsNotRevoked = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::NOT_REVOKED ]); - m_AuthorityMismatch = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::AUTHORITY_MISMATCH ]); - m_UnexpectedOwner = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::UNEXPECTED_OWNER ]); - m_NotActivated = CertificatePrivate::toBool(checks[DRing::Certificate::ChecksNames::NOT_ACTIVATED ]); -} - -void CertificatePrivate::loadDetails(bool reload) -{ - if (!m_pDetailsCache || reload) { - MapStringString d; - switch(m_LoadingType) { - case LoadingType::FROM_PATH: - d = ConfigurationManager::instance().getCertificateDetailsPath(m_Path, m_PrivateKey, m_PrivateKeyPassword); - break; - case LoadingType::FROM_ID: - d = ConfigurationManager::instance().getCertificateDetails(m_Id); - break; - } - m_pDetailsCache = new DetailsCache(d); - } -} - -void CertificatePrivate::loadChecks(bool reload) -{ - if ((!m_pCheckCache) || reload) { - MapStringString checks; - switch(m_LoadingType) { - case LoadingType::FROM_PATH: - checks = ConfigurationManager::instance().validateCertificatePath(QString(),m_Path,m_PrivateKey, m_PrivateKeyPassword, {}); - break; - case LoadingType::FROM_ID: - checks = ConfigurationManager::instance().validateCertificate(QString(),m_Id); - break; - } - if (reload && m_pCheckCache) - delete m_pCheckCache; - m_pCheckCache = new ChecksCache(checks); - CertificateModel::instance().d_ptr->regenChecks(q_ptr); - } -} - -Certificate::Certificate(const QString& path, Type type, const QString& privateKey) : ItemBase(nullptr),d_ptr(new CertificatePrivate(this,LoadingType::FROM_PATH)) -{ - Q_UNUSED(privateKey) - moveToThread(CertificateModel::instance().thread()); - setParent(&CertificateModel::instance()); - d_ptr->m_Path = path; - d_ptr->m_Type = type; -} - -Certificate::Certificate(const QString& id) : ItemBase(nullptr),d_ptr(new CertificatePrivate(this,LoadingType::FROM_ID)) -{ - moveToThread(CertificateModel::instance().thread()); - setParent(&CertificateModel::instance()); - d_ptr->m_Id = id.toLatin1(); -} - -Certificate::~Certificate() -{ - delete d_ptr; -} - -bool Certificate::hasRemote() const -{ - return ! d_ptr->m_Id.isEmpty(); -} - -QByteArray Certificate::remoteId() const -{ - return d_ptr->m_Id; -} - -QString Certificate::getName(Certificate::Checks check) -{ - return CertificatePrivate::m_slChecksName[check]; -} - -QString Certificate::getName(Certificate::Details detail) -{ - return CertificatePrivate::m_slDetailssName[detail]; -} - -QString Certificate::getDescription(Certificate::Checks check) -{ - return CertificatePrivate::m_slChecksDescription[check]; -} - -QString Certificate::getDescription(Certificate::Details detail) -{ - return CertificatePrivate::m_slDetailssDescription[detail]; -} - -Certificate::CheckValues Certificate::hasPrivateKey() const -{ - d_ptr->loadChecks(); - - if (!d_ptr->m_RequirePrivateKey) - return Certificate::CheckValues::UNSUPPORTED; - - if (!d_ptr->m_PrivateKey.isEmpty()) - return Certificate::CheckValues::PASSED; - - return d_ptr->m_pCheckCache->m_HasPrivateKey; -} - -Certificate::CheckValues Certificate::isNotExpired() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_IsExpired; -} - -Certificate::CheckValues Certificate::hasStrongSigning() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_HasStrongSigning; -} - -Certificate::CheckValues Certificate::isNotSelfSigned() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_IsSelfSigned; -} - -Certificate::CheckValues Certificate::privateKeyMatch() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_PrivateKeyMatch; -} - -Certificate::CheckValues Certificate::arePrivateKeyStoragePermissionOk() const -{ - if ((!d_ptr->m_RequirePrivateKey) || !d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePrivateKeyStoragePermissionOk; -} - -Certificate::CheckValues Certificate::arePublicKeyStoragePermissionOk() const -{ - if (!d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePublicKeyStoragePermissionOk; -} - -Certificate::CheckValues Certificate::arePrivateKeyDirectoryPermissionsOk() const -{ - if ((!d_ptr->m_RequirePrivateKey) || !d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePrivateKeyDirectoryPermissionsOk; -} - -Certificate::CheckValues Certificate::arePublicKeyDirectoryPermissionsOk() const -{ - if (!d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePublicKeyDirectoryPermissionsOk; -} - -Certificate::CheckValues Certificate::arePrivateKeyStorageLocationOk() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePrivateKeyStorageLocationOk; -} - -Certificate::CheckValues Certificate::arePublicKeyStorageLocationOk() const -{ - if (!d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePublicKeyStorageLocationOk; -} - -Certificate::CheckValues Certificate::arePrivateKeySelinuxAttributesOk() const -{ - if ((!d_ptr->m_RequirePrivateKey) || !d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePrivateKeySelinuxAttributesOk; -} - -Certificate::CheckValues Certificate::arePublicKeySelinuxAttributesOk() const -{ - if (!d_ptr->m_RequireStrictPermissions) - return Certificate::CheckValues::UNSUPPORTED; - - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ArePublicKeySelinuxAttributesOk; -} - -Certificate::CheckValues Certificate::exist() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_Exist; -} - -Certificate::CheckValues Certificate::isValid() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_IsValid; -} - -Certificate::CheckValues Certificate::hasValidAuthority() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_ValidAuthority; -} - -Certificate::CheckValues Certificate::hasKnownAuthority() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_HasKnownAuthority; -} - -Certificate::CheckValues Certificate::isNotRevoked() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_IsNotRevoked; -} - -Certificate::CheckValues Certificate::authorityMatch() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_AuthorityMismatch; -} - -Certificate::CheckValues Certificate::hasExpectedOwner() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pCheckCache->m_UnexpectedOwner; -} - -QDateTime Certificate::expirationDate() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_ExpirationDate; -} - -QDateTime Certificate::activationDate() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_ActivationDate; -} - -bool Certificate::requirePrivateKeyPassword() const -{ - if (!d_ptr->m_RequirePrivateKey) - return false; - - d_ptr->loadDetails(true); - return d_ptr->m_pDetailsCache->m_RequirePrivateKeyPassword; -} - -QString Certificate::privateKeyPassword() const -{ - return d_ptr->m_PrivateKeyPassword; -} - -QByteArray Certificate::publicSignature() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_PublicSignature; -} - -int Certificate::versionNumber() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_VersionNumber; -} - -QByteArray Certificate::serialNumber() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_SerialNumber; -} - -QString Certificate::issuer() const -{ - d_ptr->loadDetails(); - - if (d_ptr->m_pDetailsCache->m_Issuer == DRing::Certificate::CheckValuesNames::UNSUPPORTED) - d_ptr->m_pDetailsCache->m_Issuer.clear(); - - return d_ptr->m_pDetailsCache->m_Issuer; -} - -QByteArray Certificate::subjectKeyAlgorithm() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_SubjectKeyAlgorithm; -} - -QString Certificate::cn() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_Cn; -} - -QString Certificate::n() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_N; -} - -QString Certificate::o() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_O; -} - -QByteArray Certificate::signatureAlgorithm() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_SignatureAlgorithm; -} - -QByteArray Certificate::md5Fingerprint() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_Md5Fingerprint; -} - -QByteArray Certificate::sha1Fingerprint() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_Sha1Fingerprint; -} - -QByteArray Certificate::publicKeyId() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_PublicKeyId; -} - -QByteArray Certificate::issuerDn() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_IssuerDn; -} - -QDateTime Certificate::nextExpectedUpdateDate() const -{ - d_ptr->loadDetails(); - return d_ptr->m_pDetailsCache->m_NextExpectedUpdateDate; -} - -bool Certificate::isActivated() const { - d_ptr->loadDetails(); - return d_ptr->m_pCheckCache->m_NotActivated == Certificate::CheckValues::PASSED; -} - -void Certificate::setPath(const QString& path) -{ - d_ptr->m_Path = path; -} - -QString Certificate::path() const -{ - return d_ptr->m_Path; -} - -void Certificate::setPrivateKeyPath(const QString& path) -{ - d_ptr->m_PrivateKey = path; - d_ptr->m_RequirePrivateKey = true; - - //Reload the checks if necessary - if (d_ptr->m_pCheckCache) - d_ptr->loadChecks(true); -} - -void Certificate::setPrivateKeyPassword(const QString& pass) -{ - if(!requirePrivateKeyPassword()) - return; - d_ptr->m_PrivateKeyPassword = pass; - - //Reload the checks with the new password - d_ptr->loadChecks(true); -} - -QString Certificate::privateKeyPath() const -{ - return d_ptr->m_PrivateKey; -} - -Certificate::Type Certificate::type() const -{ - return d_ptr->m_Type; -} - -QString Certificate::outgoingServer() const -{ - d_ptr->loadChecks(); - return d_ptr->m_pDetailsCache->m_OutgoingServer; -} - -///This attribute can be set if the private key will be required at some point -void Certificate::setRequirePrivateKey(bool value) -{ - d_ptr->m_RequirePrivateKey = value; -} - -///This attribute can be set if the private key will be required at some point -bool Certificate::requirePrivateKey() const -{ - return d_ptr->m_RequirePrivateKey; -} - -void Certificate::setRequireStrictPermission(bool value) -{ - d_ptr->m_RequireStrictPermissions = value; -} - -bool Certificate::requireStrictPermission() const -{ - return d_ptr->m_RequireStrictPermissions; -} - -Certificate* Certificate::signedBy() const -{ - if ((!d_ptr->m_pSignedBy) && (!issuer().isEmpty())) { - d_ptr->m_pSignedBy = CertificateModel::instance().getCertificateFromId(issuer()); - } - - return d_ptr->m_pSignedBy; -} - -ChainOfTrustModel* Certificate::chainOfTrustModel() const -{ - if (!d_ptr->m_pChainOfTrust) - d_ptr->m_pChainOfTrust = new ChainOfTrustModel(const_cast<Certificate*>(this)); - - return d_ptr->m_pChainOfTrust; -} - -FlagPack<Certificate::OriginHint> Certificate::originHint() const -{ - return d_ptr->m_fHints; -} - -void Certificate::addOrigin(const FlagPack<OriginHint>& hints) -{ - d_ptr->m_fHints |= hints; -} - -ContactMethod* Certificate::contactMethod() const -{ - return d_ptr->m_pContactMethod; -} - -void Certificate::setContactMethod(ContactMethod* contactMethod) -{ - d_ptr->m_pContactMethod = contactMethod; -} - -Certificate::CheckValues Certificate::checkResult(Certificate::Checks check) const -{ - switch (check) { - case Checks::HAS_PRIVATE_KEY : return hasPrivateKey (); - case Checks::EXPIRED : return isNotExpired (); - case Checks::STRONG_SIGNING : return hasStrongSigning (); - case Checks::NOT_SELF_SIGNED : return isNotSelfSigned (); - case Checks::KEY_MATCH : return privateKeyMatch (); - case Checks::PRIVATE_KEY_STORAGE_PERMISSION : return arePrivateKeyStoragePermissionOk (); - case Checks::PUBLIC_KEY_STORAGE_PERMISSION : return arePublicKeyStoragePermissionOk (); - case Checks::PRIVATE_KEY_DIRECTORY_PERMISSIONS : return arePrivateKeyDirectoryPermissionsOk (); - case Checks::PUBLIC_KEY_DIRECTORY_PERMISSIONS : return arePublicKeyDirectoryPermissionsOk (); - case Checks::PRIVATE_KEY_STORAGE_LOCATION : return arePrivateKeyStorageLocationOk (); - case Checks::PUBLIC_KEY_STORAGE_LOCATION : return arePublicKeyStorageLocationOk (); - case Checks::PRIVATE_KEY_SELINUX_ATTRIBUTES : return arePrivateKeySelinuxAttributesOk (); - case Checks::PUBLIC_KEY_SELINUX_ATTRIBUTES : return arePublicKeySelinuxAttributesOk (); - case Checks::EXIST : return exist (); - case Checks::VALID : return isValid (); - case Checks::VALID_AUTHORITY : return hasValidAuthority (); - case Checks::KNOWN_AUTHORITY : return hasKnownAuthority (); - case Checks::NOT_REVOKED : return isNotRevoked (); - case Checks::AUTHORITY_MATCH : return authorityMatch (); - case Checks::EXPECTED_OWNER : return hasExpectedOwner (); - case Checks::ACTIVATED : return static_cast<Certificate::CheckValues>(isActivated()); - case Checks::COUNT__: - Q_ASSERT(false); - }; - return Certificate::CheckValues::UNSUPPORTED; -} - -QVariant Certificate::detailResult(Certificate::Details detail) const -{ - switch(detail) { - case Details::EXPIRATION_DATE : return expirationDate (); - case Details::ACTIVATION_DATE : return activationDate (); - case Details::REQUIRE_PRIVATE_KEY_PASSWORD : return requirePrivateKeyPassword (); - case Details::PUBLIC_SIGNATURE : return publicSignature (); - case Details::VERSION_NUMBER : return versionNumber (); - case Details::SERIAL_NUMBER : return serialNumber (); - case Details::ISSUER : return issuer (); - case Details::SUBJECT_KEY_ALGORITHM : return subjectKeyAlgorithm (); - case Details::CN : return cn (); - case Details::N : return n (); - case Details::O : return o (); - case Details::SIGNATURE_ALGORITHM : return signatureAlgorithm (); - case Details::MD5_FINGERPRINT : return md5Fingerprint (); - case Details::SHA1_FINGERPRINT : return sha1Fingerprint (); - case Details::PUBLIC_KEY_ID : return publicKeyId (); - case Details::ISSUER_DN : return issuerDn (); - case Details::NEXT_EXPECTED_UPDATE_DATE : return nextExpectedUpdateDate (); - case Details::OUTGOING_SERVER : return outgoingServer (); - - case Details::COUNT__: - Q_ASSERT(false); - }; - return QVariant(); -} - -/** - * Get the details of this certificate as a QAbstractItemModel - * - * Please note that the object ownership will be transferred. To avoid memory - * leaks, the users of this object must delete it once they are done with it. - */ -QAbstractItemModel* Certificate::model() const -{ - return CertificateModel::instance().d_ptr->model(this); -} - -/** - * This model further reduce the data to only return the relevant certificate - * checks. - */ -QAbstractItemModel* Certificate::checksModel() const -{ - return CertificateModel::instance().d_ptr->checksModel(this); -} - -///DEPRECATED -bool Certificate::setStatus(const Account* a, Status s) -{ - if (!a) - return false; - - //This status is stored as a 3bit bitmask in 3 64bit integers - - const int maskId = a->internalId(); - const int position = (maskId*3)/64; - const int offset = (maskId*3)%64; - - //Only 63 accounts are currently supported - if (position > 3) - return false; - - d_ptr->m_Statuses[position] = static_cast<int>(s) << offset; - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - //Notify the daemon - if (hasRemote()) { - configurationManager.setCertificateStatus(a->id(),d_ptr->m_Id,CertificateModelPrivate::m_StatusMap[s]); - } - else { - //d_ptr->m_Id = configurationManager.pinCertificatePath(path()); - //TODO register the certificate in the daemon - } - - return true; -} - -///DEPRECATED -Certificate::Status Certificate::status(const Account* a) const -{ - const int maskId = a->internalId(); - const int position = (maskId*3)/64; - const int offset = (maskId*3)%64; - - if (position >= 3) - return Certificate::Status::UNDEFINED; - - const int raw = (d_ptr->m_Statuses[position] >> offset) & 0b111; - - Q_ASSERT(raw < enum_class_size<Certificate::Status>()); - - return static_cast<Certificate::Status>(raw); -} - -bool Certificate::fixPermissions() const -{ -#ifndef Q_OS_WIN - if (d_ptr->m_LoadingType != LoadingType::FROM_PATH) - return false; - - bool ret = true; - - QFile publicKey(d_ptr->m_Path); - - if (!publicKey.exists()) { - qWarning() << "The public key" << d_ptr->m_Path << "doesn't exist"; - ret &= false; - } - - const bool publicperm = publicKey.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner); - ret &= publicperm; - - if (!publicperm) - qWarning() << "Setting the public key" << d_ptr->m_Path << "permissions failed"; - - if (!d_ptr->m_PrivateKey.isEmpty()) { - QFile privateKey(d_ptr->m_PrivateKey); - - if (!privateKey.exists()) { - qWarning() << "The private key" << d_ptr->m_PrivateKey << "doesn't exist"; - ret &= false; - } - - const bool privperm = privateKey.setPermissions(QFileDevice::ReadOwner | QFileDevice::WriteOwner); - ret &= privperm; - - if (!privperm) - qWarning() << "Setting the private key" << d_ptr->m_PrivateKey << "permissions failed"; - } - - d_ptr->loadChecks(true); - emit changed(); - - return ret; - -#else - return false; -#endif -} - -bool Certificate::moveToDotCert() const -{ -//TODO implement for OSX and Windows -#ifdef Q_OS_LINUX - if (d_ptr->m_LoadingType != LoadingType::FROM_PATH) - return false; - - bool ret = true; - - QFile publicKey(d_ptr->m_Path); - - if (!publicKey.exists()) { - qWarning() << "The public key" << d_ptr->m_Path << "doesn't exist"; - ret &= false; - } - - QDir certDir(QDir::homePath()+".cert"); - - if (!certDir.exists()) { - const bool mk = QDir(QDir::homePath()).mkdir(".cert"); - if (!mk) - qWarning() << "Creating" << (QDir::homePath()+"/.cert") << "failed"; - - ret &= mk; - } - - ret &= publicKey.rename(QString("/home/%1/.cert/%2/") - .arg( QDir::homePath () ) - .arg( publicKey.fileName () ) - ); - - if (!d_ptr->m_PrivateKey.isEmpty()) { - QFile privateKey(d_ptr->m_PrivateKey); - - if (!privateKey.exists()) { - qWarning() << "The private key" << d_ptr->m_Path << "doesn't exist"; - ret &= false; - } - - ret &= privateKey.rename(QString("/home/%1/.cert/%2/") - .arg( QDir::homePath () ) - .arg( privateKey.fileName () ) - ); - } - - d_ptr->loadChecks(true); - emit changed(); - - return ret; - -#else - return false; -#endif -} - -/** - * get the data by role selection - * @param role define the role to select - * @return a QVariant object, which contains the selection - */ -QVariant -Certificate::roleData(int role) const -{ - switch (role) { - case Qt::DisplayRole: - case Qt::EditRole: - return remoteId(); - case static_cast<int>(Ring::Role::Object): - return QVariant::fromValue(const_cast<Certificate*>(this)); - case static_cast<int>(Ring::Role::ObjectType): - return QVariant::fromValue(Ring::ObjectType::Certificate); - } - - /* unknown role */ - return QVariant(); -} - -#include <certificate.moc> diff --git a/src/certificate.h b/src/certificate.h deleted file mode 100644 index 60eeeac8b79ec5de5583586f1c4388a288bc3cbb..0000000000000000000000000000000000000000 --- a/src/certificate.h +++ /dev/null @@ -1,323 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" -#include "itembase.h" - -//Qt -class QAbstractItemModel; - -class CertificatePrivate; -class Account; -class ChainOfTrustModel; -class ContactMethod; - -/** - * This class represent a conceptual certificate. - */ -class LIB_EXPORT Certificate : public ItemBase -{ - Q_OBJECT - - friend class CertificateModel; - friend class CertificateModelPrivate; - friend class SecurityEvaluationModel; - friend class SecurityEvaluationModelPrivate; -public: - - //Properties - Q_PROPERTY(CheckValues hasPrivateKey READ hasPrivateKey ) - Q_PROPERTY(CheckValues isNotExpired READ isNotExpired ) - Q_PROPERTY(CheckValues hasStrongSigning READ hasStrongSigning ) - Q_PROPERTY(CheckValues isNotSelfSigned READ isNotSelfSigned ) - Q_PROPERTY(CheckValues privateKeyMatch READ privateKeyMatch ) - Q_PROPERTY(CheckValues arePrivateKeyStoragePermissionOk READ arePrivateKeyStoragePermissionOk ) - Q_PROPERTY(CheckValues arePublicKeyStoragePermissionOk READ arePublicKeyStoragePermissionOk ) - Q_PROPERTY(CheckValues arePrivateKeyDirectoryPermissionsOk READ arePrivateKeyDirectoryPermissionsOk ) - Q_PROPERTY(CheckValues arePublicKeyDirectoryPermissionsOk READ arePublicKeyDirectoryPermissionsOk ) - Q_PROPERTY(CheckValues arePrivateKeyStorageLocationOk READ arePrivateKeyStorageLocationOk ) - Q_PROPERTY(CheckValues arePublicKeyStorageLocationOk READ arePublicKeyStorageLocationOk ) - Q_PROPERTY(CheckValues arePrivateKeySelinuxAttributesOk READ arePrivateKeySelinuxAttributesOk ) - Q_PROPERTY(CheckValues arePublicKeySelinuxAttributesOk READ arePublicKeySelinuxAttributesOk ) - Q_PROPERTY(CheckValues exist READ exist ) - Q_PROPERTY(CheckValues isValid READ isValid ) - Q_PROPERTY(CheckValues hasValidAuthority READ hasValidAuthority ) - Q_PROPERTY(CheckValues hasKnownAuthority READ hasKnownAuthority ) - Q_PROPERTY(CheckValues isNotRevoked READ isNotRevoked ) - Q_PROPERTY(CheckValues authorityMatch READ authorityMatch ) - Q_PROPERTY(CheckValues hasExpectedOwner READ hasExpectedOwner ) - Q_PROPERTY(bool isActivated READ isActivated ) - Q_PROPERTY(bool hasRemote READ hasRemote ) - Q_PROPERTY(QByteArray remoteId READ remoteId ) - Q_PROPERTY(QString path READ path WRITE setPath ) - Q_PROPERTY(QString privateKeyPath READ privateKeyPath WRITE setPrivateKeyPath) - - Q_PROPERTY(QDateTime expirationDate READ expirationDate ) - Q_PROPERTY(QDateTime activationDate READ activationDate ) - Q_PROPERTY(bool requirePrivateKeyPassword READ requirePrivateKeyPassword) - Q_PROPERTY(QByteArray publicSignature READ publicSignature ) - Q_PROPERTY(int versionNumber READ versionNumber ) - Q_PROPERTY(QByteArray serialNumber READ serialNumber ) - Q_PROPERTY(QString issuer READ issuer ) - Q_PROPERTY(QByteArray subjectKeyAlgorithm READ subjectKeyAlgorithm ) - Q_PROPERTY(QString cn READ cn ) - Q_PROPERTY(QString n READ n ) - Q_PROPERTY(QString o READ o ) - Q_PROPERTY(QByteArray signatureAlgorithm READ signatureAlgorithm ) - Q_PROPERTY(QByteArray md5Fingerprint READ md5Fingerprint ) - Q_PROPERTY(QByteArray sha1Fingerprint READ sha1Fingerprint ) - Q_PROPERTY(QByteArray publicKeyId READ publicKeyId ) - Q_PROPERTY(QByteArray issuerDn READ issuerDn ) - Q_PROPERTY(QDateTime nextExpectedUpdateDate READ nextExpectedUpdateDate ) - Q_PROPERTY(QString outgoingServer READ outgoingServer ) - Q_PROPERTY(ContactMethod* contactMethod READ contactMethod WRITE setContactMethod) - - - //Structures - - /** - * Represent a certificate "reason to be" in the system. - * - * Certificates can be there for multiple reasons, they are flags. It will be - * used as hints in other subsystem. - */ - enum class OriginHint { - UNKNOWN = 0x0 , /*!< The origin isn't known */ - SYSTEM_AUTHORITY = 0x1 << 0, /*!< The certificate is part of the system wide store */ - ROOT_AUTORITY = 0x1 << 1, /*!< The certificate is part of the system wide root store */ - INTERMEDIATE_AUTHORITY = 0x1 << 2, /*!< The certificate is part of the chain between a system certificate and another one */ - ACCOUNT_AUTHORITY = 0x1 << 3, /*!< The certificate is used as CA by an account */ - ACCOUNT_KEY = 0x1 << 4, /*!< The certificate is used as a key by an account */ - PERSON = 0x1 << 5, /*!< The certificate is associated with a person */ - BLACKLIST = 0x1 << 6, /*!< This certificate is part of an account communication blacklist */ - WHITELIST = 0x1 << 7, /*!< This certificate is part of an account communication whitelist */ - HISTORY = 0x1 << 8, /*!< This certificate is used by at least one history call */ - NETWORK_PRESENCE = 0x1 << 9, /*!< This certificate is exposed by a peer on the local network */ - }; - Q_FLAGS(OriginHint) - - ///DEPRECATED - enum class Type { - AUTHORITY , - USER , - PRIVATE_KEY, - CALL , - NONE , - }; - - /** - * @enum Checks All validation fields - * - */ - enum class Checks { - HAS_PRIVATE_KEY , /*!< This certificate has a build in private key */ - EXPIRED , /*!< This certificate is past its expiration date */ - STRONG_SIGNING , /*!< This certificate has been signed with a brute-force-able method */ - NOT_SELF_SIGNED , /*!< This certificate has been self signed */ - KEY_MATCH , /*!< The public and private keys provided don't match */ - PRIVATE_KEY_STORAGE_PERMISSION , /*!< The file hosting the private key isn't correctly secured */ - PUBLIC_KEY_STORAGE_PERMISSION , /*!< The file hosting the public key isn't correctly secured */ - PRIVATE_KEY_DIRECTORY_PERMISSIONS , /*!< The folder storing the private key isn't correctly secured */ - PUBLIC_KEY_DIRECTORY_PERMISSIONS , /*!< The folder storing the public key isn't correctly secured */ - PRIVATE_KEY_STORAGE_LOCATION , /*!< Some operating systems have extra policies for certificate storage */ - PUBLIC_KEY_STORAGE_LOCATION , /*!< Some operating systems have extra policies for certificate storage */ - PRIVATE_KEY_SELINUX_ATTRIBUTES , /*!< Some operating systems require keys to have extra attributes */ - PUBLIC_KEY_SELINUX_ATTRIBUTES , /*!< Some operating systems require keys to have extra attributes */ - EXIST , /*!< The certificate file doesn't exist or is not accessible */ - VALID , /*!< The file is not a certificate */ - VALID_AUTHORITY , /*!< The claimed authority did not sign the certificate */ - KNOWN_AUTHORITY , /*!< Some operating systems provide a list of trusted authorities, use it */ - NOT_REVOKED , /*!< The certificate has been revoked by the authority */ - AUTHORITY_MATCH , /*!< The certificate and authority mismatch */ - EXPECTED_OWNER , /*!< The certificate has an expected owner */ - ACTIVATED , /*!< The certificate has not been activated yet */ - COUNT__, - }; - - /** - * @enum Details Informative fields about a certificate - */ - enum class Details { - EXPIRATION_DATE , /*!< The certificate expiration date */ - ACTIVATION_DATE , /*!< The certificate activation date */ - REQUIRE_PRIVATE_KEY_PASSWORD , /*!< Does the private key require a password */ - PUBLIC_SIGNATURE , - VERSION_NUMBER , - SERIAL_NUMBER , - ISSUER , - SUBJECT_KEY_ALGORITHM , - CN , - N , - O , - SIGNATURE_ALGORITHM , - MD5_FINGERPRINT , - SHA1_FINGERPRINT , - PUBLIC_KEY_ID , - ISSUER_DN , - NEXT_EXPECTED_UPDATE_DATE , - OUTGOING_SERVER , /*!< The hostname/outgoing server used for this certificate */ - - COUNT__ - }; - - /** - * @enum CheckValuesType Categories of possible values for each Checks - */ - enum class CheckValuesType { - BOOLEAN, - ISO_DATE, - CUSTOM, - NUMBER, - COUNT__, - }; - - /** - * @enum CheckValue possible values for check - * - * All boolean check use PASSED when the test result is positive and - * FAILED when it is negative. All new check need to keep this convention - * or ::isValid() result will become unrepresentative of the real state. - * - * CUSTOM should be avoided when possible. This enum can be extended when - * new validated types are required. - */ - enum class CheckValues { - FAILED , /*!< Equivalent of a boolean "false" */ - PASSED , /*!< Equivalent of a boolean "true" */ - UNSUPPORTED, /*!< The operating system doesn't support or require the check */ - COUNT__, - }; - Q_ENUMS(CheckValues) - - /** - * A certificate local status. A single certificate can have multiple status - * at once depending on the context. For example, one account may block a - * certificate while another one trust it. - */ - enum class Status { - UNDEFINED , - ALLOWED , - BANNED , - REVOKED , - REVOKED_ALLOWED, - COUNT__ - }; - Q_ENUMS(Status) - - //Getter - QString path ( ) const; - QString privateKeyPath ( ) const; - Certificate::Type type ( ) const; - Certificate::CheckValues checkResult ( Certificate::Checks check ) const; - QVariant detailResult ( Certificate::Details detail ) const; - QAbstractItemModel* model ( ) const; - QAbstractItemModel* checksModel ( ) const; - bool hasRemote ( ) const; - QByteArray remoteId ( ) const; - Status status ( const Account* a ) const; - bool requireStrictPermission ( ) const; - Certificate* signedBy ( ) const; - ChainOfTrustModel* chainOfTrustModel ( ) const; - FlagPack<OriginHint> originHint ( ) const; - ContactMethod* contactMethod ( ) const; - Q_INVOKABLE QVariant roleData ( int role ) const; - - - static QString getName (Certificate::Checks check ); - static QString getName (Certificate::Details details ); - static QString getDescription (Certificate::Checks check ); - static QString getDescription (Certificate::Details details ); - - //Checks - CheckValues hasPrivateKey () const; - CheckValues isNotExpired () const; - CheckValues hasStrongSigning () const; - CheckValues isNotSelfSigned () const; - CheckValues privateKeyMatch () const; - CheckValues arePrivateKeyStoragePermissionOk () const; - CheckValues arePublicKeyStoragePermissionOk () const; - CheckValues arePrivateKeyDirectoryPermissionsOk () const; - CheckValues arePublicKeyDirectoryPermissionsOk () const; - CheckValues arePrivateKeyStorageLocationOk () const; - CheckValues arePublicKeyStorageLocationOk () const; - CheckValues arePrivateKeySelinuxAttributesOk () const; - CheckValues arePublicKeySelinuxAttributesOk () const; - CheckValues exist () const; - CheckValues isValid () const; - CheckValues hasValidAuthority () const; - CheckValues hasKnownAuthority () const; - CheckValues isNotRevoked () const; - CheckValues authorityMatch () const; - CheckValues hasExpectedOwner () const; - bool isActivated () const; - - //Details - QDateTime expirationDate () const; - QDateTime activationDate () const; - bool requirePrivateKeyPassword () const; - QString privateKeyPassword () const; - - bool requirePrivateKey () const; - QByteArray publicSignature () const; - int versionNumber () const; - QByteArray serialNumber () const; - QString issuer () const; - QByteArray subjectKeyAlgorithm () const; - QString cn () const; - QString n () const; - QString o () const; - QByteArray signatureAlgorithm () const; - QByteArray md5Fingerprint () const; - QByteArray sha1Fingerprint () const; - QByteArray publicKeyId () const; - QByteArray issuerDn () const; - QDateTime nextExpectedUpdateDate () const; - QString outgoingServer () const; - - //Setter - void setPath(const QString& path); - bool setStatus(const Account* a, Status s); - void setPrivateKeyPath(const QString& path); - void setPrivateKeyPassword(const QString& pass); - void setRequirePrivateKey(bool value); - void setRequireStrictPermission(bool value); - void addOrigin(const FlagPack<OriginHint>& hints); - void setContactMethod(ContactMethod* contactMethod); - - //Mutator - Q_INVOKABLE bool fixPermissions() const; - Q_INVOKABLE bool moveToDotCert () const; - -private: - explicit Certificate(const QString& path, Type type, const QString& privateKey = QString()); - Certificate(const QString& id); - Certificate(const QByteArray& content, Type type = Type::CALL); - virtual ~Certificate(); - CertificatePrivate* d_ptr; - -Q_SIGNALS: - ///This certificate changed, all users need to reload it - void changed() const; -}; -Q_DECLARE_METATYPE(Certificate*) -Q_DECLARE_METATYPE(Certificate::CheckValues) -Q_DECLARE_METATYPE(Certificate::Checks) -Q_DECLARE_METATYPE(Certificate::Details) -Q_DECLARE_METATYPE(Certificate::Status) - diff --git a/src/certificatemodel.cpp b/src/certificatemodel.cpp deleted file mode 100644 index 1ea213b30da46984426dda40d5902b479c270051..0000000000000000000000000000000000000000 --- a/src/certificatemodel.cpp +++ /dev/null @@ -1,1019 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "certificatemodel.h" - -//Qt -#include <QtCore/QCoreApplication> -#include <QtCore/QObject> -#include <QtCore/QCryptographicHash> -#include <QtCore/QThread> -#include <QtCore/QMutex> -#include <QtCore/QMutexLocker> -#include <QtCore/QAbstractProxyModel> - -//LibSTDC++ -#include <functional> - -//Dring -#include "dbus/configurationmanager.h" -#include "security_const.h" - -//Ring -#include "certificate.h" -#include "contactmethod.h" -#include "account.h" -#include "private/matrixutils.h" -#include "private/certificatemodel_p.h" -#include "accountmodel.h" - -/* - * This data structure is a graph wrapping the certificates in different contexts. - * - * For example, a single certificate can be allowed for an account and banned for - * another. Then, there is also the notion of "known" certificates for an account - * that's independent from the certificate state. - * - * This class store bunch of "groups" associated with accounts. Each certificate - * can be part of multiple groups. - * - * Levels: - * 1: Root (tree) - * 2: Groups (tree) - * 3: Certificate (graph) - * 4: Certificate elements - * 5.1: Certificate details - * 5.2: Certificate security checks - * - * Structures: - * CertificateNode: metadata associated with the certificate - * CertificateNodeWrapper: A single path in the graph - * - * It is a graph, but it's usually handled as a tree. The only layer of the tree - * with graph characteristic is the certificate level. - * - * The purpose of this is to be able to create model proxies for various type - * of information based on the same memory tree. - * - */ - -enum class DetailType : uchar -{ - NONE , - DETAIL, - CHECK , -}; - - -struct CertificateNode { - - CertificateNode(int index, CertificateModel::NodeType level, CertificateNode* parent, Certificate* cert); - ~CertificateNode(); - void setStrings(const QString& col1, const QVariant& col2, const QString& tooltip); - - //Attributes - QVector<CertificateNode*> m_lChildren ; - CertificateNode* m_pParent ; - Certificate* m_pCertificate ; - CertificateModel::NodeType m_Level ; - DetailType m_DetailType ; - int m_Index ; - int m_EnumClassDetail; - QString m_Col1 ; - QVariant m_Col2 ; - QString m_ToolTip ; - std::function<void()> m_fLoader ; - bool m_IsLoaded ; - int m_CatIdx ; - unsigned long long m_fIsPartOf ; - QHash<Account*,CertificateNode*> m_hSiblings; -}; - -class CertificateProxyModel final : public QAbstractProxyModel -{ - Q_OBJECT -public: - CertificateProxyModel(CertificateModel* parent, CertificateNode* root); - - //Model implementation - virtual QModelIndex mapFromSource( const QModelIndex& sourceIndex ) const override; - virtual QModelIndex mapToSource ( const QModelIndex& proxyIndex ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - -private: - CertificateNode* m_pRoot; -}; - -const Matrix1D<Certificate::Status, const char*> CertificateModelPrivate::m_StatusMap = {{ -/* Certificate::Status::UNDEFINED */ DRing::Certificate::Status::UNDEFINED, -/* Certificate::Status::ALLOWED */ DRing::Certificate::Status::ALLOWED , -/* Certificate::Status::BANNED */ DRing::Certificate::Status::BANNED , -/* Certificate::Status::REVOKED */ "" , -/* Certificate::Status::REVOKED_ALLOWED*/ DRing::Certificate::Status::ALLOWED , -}}; - -CertificateModelPrivate::~CertificateModelPrivate() -{ - foreach(CertificateNode* node, m_lTopLevelNodes) { - delete node->m_pCertificate; - delete node; - } -} - -CertificateNode::CertificateNode(int index, CertificateModel::NodeType level, CertificateNode* parent, Certificate* cert) : - m_pParent(parent), m_pCertificate(cert), m_Level(level), m_Index(index), m_IsLoaded(true),m_DetailType(DetailType::NONE), - m_EnumClassDetail(0),m_CatIdx(-1),m_fIsPartOf(0) -{ - if (level == CertificateModel::NodeType::CATEGORY ) - m_CatIdx = ++(CertificateModel::instance().d_ptr->m_GroupCounter); - - CertificateNode* sibling = CertificateModel::instance().d_ptr->m_hNodes[cert]; - - if (parent && sibling && parent->m_Level == CertificateModel::NodeType::CATEGORY) - sibling->m_fIsPartOf |= (0x01 << parent->m_CatIdx); - else - CertificateModel::instance().d_ptr->m_hNodes[cert] = this; - - if (parent && parent->m_Level == CertificateModel::NodeType::CATEGORY) - m_fIsPartOf |= (0x01 << parent->m_CatIdx); -} - -CertificateNode::~CertificateNode() -{ - for (CertificateNode* c : m_lChildren) - delete c; -} - -CertificateModelPrivate::CertificateModelPrivate(CertificateModel* parent) : QObject(parent), q_ptr(parent), - m_pDefaultCategory(nullptr), m_CertLoader(), m_GroupCounter(-1) -{ - connect(&ConfigurationManager::instance(), &ConfigurationManagerInterface::certificateStateChanged, this, &CertificateModelPrivate::slotCertificateStateChanged); -} - -CertificateModel::CertificateModel(QObject* parent) : QAbstractItemModel(parent), CollectionManagerInterface<Certificate>(this), - d_ptr(new CertificateModelPrivate(this)) -{ - setObjectName("CertificateModel"); -} - -CertificateModel::~CertificateModel() -{ -} - -CertificateModel& CertificateModel::instance() -{ - static auto instance = new CertificateModel(QCoreApplication::instance()); - return *instance; -} - -QHash<int,QByteArray> CertificateModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles[static_cast<int>(Role::NodeType)] = "nodeType"; - - //Add all the details, this isn't safe because of tr(), but good enough for debugging - for (const Certificate::Details d : EnumIterator<Certificate::Details>()) { - QString name = Certificate::getName(d).toLatin1(); - while (name.indexOf(' ') != -1) { - const int idx = name.indexOf(' ') ; - name = name.remove(idx,1) ; - name[idx] = name[idx].toUpper(); - name[0 ] = name[0].toLower (); - } - roles[static_cast<int>(Role::DetailRoleBase)+static_cast<int>(d)] = name.toLatin1(); - } - - roles[static_cast<int>(Role::isDetail)] = "isDetail"; - roles[static_cast<int>(Role::isCheck )] = "isCheck" ; - roles[static_cast<int>(Role::detail )] = "detail" ; - roles[static_cast<int>(Role::check )] = "check" ; - } - return roles; -} - -void CertificateNode::setStrings(const QString& col1, const QVariant& col2, const QString& tooltip) -{ - m_Col1 = col1 ; - m_Col2 = col2 ; - m_ToolTip = tooltip; -} - -CertificateNode* CertificateModelPrivate::createCategory(const QString& name, const QString& col2, const QString& tooltip ) -{ - QMutexLocker l(&m_CertLoader); - const int idx = m_lTopLevelNodes.size(); - - // This should be avoided whenever possible. Having a duplicate would be - // both a memory leak and a potential collision attack (far fetched). - // This code avoids leak, but has side effects. - if (m_hStrToCat.contains(name)) { - qWarning() << "Trying to create a certificate node with an already used id." - " This can have unforseen consequences"; - return m_hStrToCat[name]; - } - - CertificateNode* n = new CertificateNode(idx, CertificateModel::NodeType::CATEGORY, nullptr, nullptr); - n->setStrings(name,col2,tooltip); - - q_ptr->beginInsertRows(QModelIndex(), idx, idx); - m_lTopLevelNodes << n; - q_ptr->endInsertRows(); - - m_hStrToCat[name] = n; - - return n; -} - -CertificateNode* CertificateModelPrivate::defaultCategory() -{ - if (!m_pDefaultCategory) { - m_pDefaultCategory = createCategory(QObject::tr("Default"),QObject::tr("Certificate not associated with a group"),QString()); - } - - return m_pDefaultCategory; -} - -QModelIndex CertificateModelPrivate::createIndex(int r ,int c , void* p) -{ - return q_ptr->createIndex(r,c,p); -} - -void CertificateModelPrivate::removeFromTree(CertificateNode* node) -{ - CertificateNode* parent = node->m_pParent; - const QModelIndex parentIdx = q_ptr->createIndex(parent->m_Index,0,parent); - - q_ptr->beginRemoveRows(parentIdx, node->m_Index, node->m_Index); - parent->m_lChildren.removeAt(node->m_Index); - - for(int i = node->m_Index; i < parent->m_lChildren.size(); i++) - parent->m_lChildren[i]->m_Index--; - - q_ptr->endRemoveRows(); - - //FIXME Those nodes are indexed in a few hashes, clear them - delete node; -} - -void CertificateModelPrivate::removeFromTree(Certificate* c, CertificateNode* category) -{ - if ((!c) || (!category)) - return; - - const QVector<CertificateNode*> nodes = category->m_lChildren; - - for (CertificateNode* n : nodes) { - if (n->m_pCertificate == c) - removeFromTree(n); - } -} - -CertificateNode* CertificateModelPrivate::getCategory(const Account* a) -{ - CertificateNode* cat = m_hAccToCat.value(a); - - if (!cat) { - cat = createCategory(a->alias(),QString(),QString()); - m_hAccToCat[a] = cat; - } - - return cat; -} - -//For convenience -CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, Account* a) -{ - - if (!a) - return addToTree(cert); - - CertificateNode* cat = getCategory(a); - - return addToTree(cert,cat); -} - -void CertificateModelPrivate::regenChecks(Certificate* cert) -{ - CertificateNode* n = m_hNodes.value(cert); - - if (!n) - return; - - //There could be a loading race condition - if (n->m_lChildren.size() >= 2) - loadChecks(n->m_lChildren[1], cert); -} - -//[Re]generate the checks -void CertificateModelPrivate::loadChecks(CertificateNode* checks, Certificate* cert) -{ - QMutexLocker locker(&m_CertLoader); - const QModelIndex checksI(q_ptr->createIndex(checks->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),checks)); - - //Clear the existing nodes - if (checks->m_lChildren.size()) { - q_ptr->beginRemoveRows(checksI, 0, checks->m_lChildren.size()); - const QList<CertificateNode*> nodes; - - for (CertificateNode* n : nodes) - delete n; - - checks->m_lChildren.clear(); - - q_ptr->endRemoveRows(); - } - - //Add the new ones - for (const Certificate::Checks check : EnumIterator<Certificate::Checks>()) { - if (cert->checkResult(check) != Certificate::CheckValues::UNSUPPORTED) { - q_ptr->beginInsertRows(checksI, checks->m_lChildren.size(), checks->m_lChildren.size()); - CertificateNode* d = new CertificateNode(checks->m_lChildren.size(), CertificateModel::NodeType::DETAILS, checks, nullptr); - d->setStrings(cert->getName(check),static_cast<bool>(cert->checkResult(check)),cert->getDescription(check)); - d->m_DetailType = DetailType::CHECK; - d->m_pCertificate = cert; - d->m_EnumClassDetail = static_cast<int>(check); - checks->m_lChildren << d; - q_ptr->endInsertRows(); - } else { - // unsupported check, not inserting - } - } -} - -CertificateNode* CertificateModelPrivate::addToTree(Certificate* cert, CertificateNode* category) -{ - if (!category) - category = defaultCategory(); - - // defaultCategory(); can request the mutex - QMutexLocker locker(&m_CertLoader); - - //Do not add it twice - CertificateNode* node = CertificateModel::instance().d_ptr->m_hNodes.value(cert); - - if (isPartOf(node, category)) - return node; - - const int idx = category->m_lChildren.size(); - - node = new CertificateNode(idx, CertificateModel::NodeType::CERTIFICATE, category, cert); - node->setStrings(QObject::tr("A certificate"),QObject::tr("An organisation"),QString()); - - const QModelIndex parent = q_ptr->createIndex(category->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),category); - q_ptr->beginInsertRows(parent, idx, idx); - category->m_lChildren << node; - q_ptr->endInsertRows(); - - //Lazy loaded function to reduce the overhead of this (mostly hidden) model - node->m_fLoader = [this,node,cert]() { - CertificateNode* checks = nullptr; - { // mutex - node->m_Col1 = cert->detailResult(Certificate::Details::PUBLIC_KEY_ID).toString(); - node->m_IsLoaded = true; - const QModelIndex index = q_ptr->createIndex(node->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),node); - - CertificateNode* details = nullptr; - - //Insert the check and details categories - { // mutex - QMutexLocker locker(&m_CertLoader); - q_ptr->beginInsertRows(index, 0, 1); - details = new CertificateNode(static_cast<int>(CertificateModel::Columns::NAME ), CertificateModel::NodeType::DETAILS_CATEGORY, node, nullptr); - checks = new CertificateNode(static_cast<int>(CertificateModel::Columns::VALUE), CertificateModel::NodeType::DETAILS_CATEGORY, node, nullptr); - details->setStrings(QObject::tr("Details"),QString(),QObject::tr("The content of the certificate") ); - checks ->setStrings(QObject::tr("Checks") ,QString(),QObject::tr("Various security related information") ); - node->m_lChildren << details; - node->m_lChildren << checks; - q_ptr->endInsertRows(); - } // mutex - - static const int detailsC(enum_class_size<Certificate::Details>()); - - const QModelIndex detailsI(q_ptr->createIndex(details->m_Index,static_cast<int>(CertificateModel::Columns::NAME ),details)); - - // Make sure the lazy-loaded details have been created (otherwise it will deadlock) - for (const Certificate::Details detail : EnumIterator<Certificate::Details>()) { - cert->getName (detail); - cert->detailResult (detail); - cert->getDescription(detail); - } - - //Insert the details - { // mutex - QMutexLocker locker(&m_CertLoader); - q_ptr->beginInsertRows(detailsI, 0, detailsC - 1); - for (const Certificate::Details detail : EnumIterator<Certificate::Details>()) { - CertificateNode* d = new CertificateNode(details->m_lChildren.size(), CertificateModel::NodeType::DETAILS, details, nullptr); - d->setStrings(cert->getName(detail),cert->detailResult(detail),cert->getDescription(detail)); - d->m_DetailType = DetailType::DETAIL; - d->m_pCertificate = cert; - d->m_EnumClassDetail = static_cast<int>(detail); - details->m_lChildren << d; - } - q_ptr->endInsertRows(); - } // mutex - - } // mutex - - //Insert the checks - this->loadChecks(checks, cert); - }; - node->m_IsLoaded = false; - - return node; -} - -bool CertificateModelPrivate::isPartOf(CertificateNode* sibling, CertificateNode* list) -{ - if (!list) { - qWarning() << "CertificateModelPrivate::isPartOf called on empty list"; - return false; - } - - return sibling && sibling->m_fIsPartOf & (1 << list->m_CatIdx); -} - -bool CertificateModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - - return false; -} - -QVariant CertificateModel::data( const QModelIndex& index, int role) const -{ - Q_UNUSED(role) - if (!index.isValid()) - return QVariant(); - const CertificateNode* node = static_cast<CertificateNode*>(index.internalPointer()); - - if (!node) - return QVariant(); - - if (node->m_Level == NodeType::CERTIFICATE) { - - // If the certificate has a contactMethod, implement the generic LRC roles - // this is used to match trust requests or white/blacklist entries with - // peoples. - if (node->m_pCertificate && node->m_pCertificate->contactMethod() && ( - role == Qt::DisplayRole || role == Qt::DecorationRole || ( - role > static_cast<int>(Ring::Role::Object) - && role < static_cast<int>(Ring::Role::UnreadTextMessageCount) - ) - )) { - switch(role) { - case static_cast<int>(Ring::Role::Object): - return QVariant::fromValue(node->m_pCertificate); - case static_cast<int>(Ring::Role::ObjectType): - return QVariant::fromValue(Ring::ObjectType::Certificate); - default: - return node->m_pCertificate->contactMethod()->roleData(role); - } - } - // Add the details as roles for certificates - else if (role >= static_cast<int>(Role::DetailRoleBase) && role < static_cast<int>(Role::DetailRoleBase)+enum_class_size<Certificate::Details>()) { - Certificate* cert = node->m_pCertificate; - if (cert) { - return cert->detailResult(static_cast<Certificate::Details>(role - static_cast<int>(Role::DetailRoleBase))); - } - } - } - - switch(role) { - case Qt::DisplayRole: - case Qt::EditRole: - return index.column()?node->m_Col2:node->m_Col1; - case Qt::ToolTipRole: - return node->m_ToolTip; - case static_cast<int>(Role::NodeType): - return QVariant::fromValue(node->m_Level); - }; - - switch (node->m_Level) { - case CertificateModel::NodeType::DETAILS : - switch(role) { - case (int)Role::isDetail: - return node->m_DetailType == DetailType::DETAIL; - case (int)Role::isCheck: - return node->m_DetailType == DetailType::CHECK; - case (int)Role::detail: - if (node->m_DetailType == DetailType::DETAIL) - return QVariant::fromValue(static_cast<Certificate::Details>(node->m_EnumClassDetail)); - break; - case (int)Role::check: - if (node->m_DetailType == DetailType::CHECK) - return QVariant::fromValue(static_cast<Certificate::Checks>(node->m_EnumClassDetail)); - break; - case (int)Role::requirePrivateKey: - return node->m_pCertificate ? node->m_pCertificate->requirePrivateKey() : false; - } - break; - case CertificateModel::NodeType::CERTIFICATE : - case CertificateModel::NodeType::DETAILS_CATEGORY: - case CertificateModel::NodeType::CATEGORY : - break; - } - - return QVariant(); -} - -int CertificateModel::rowCount( const QModelIndex& parent) const -{ - if (!parent.isValid()) - return d_ptr->m_lTopLevelNodes.size(); - else { - const CertificateNode* node = static_cast<CertificateNode*>(parent.internalPointer()); - - //Load that info only when it is needed - if (node->m_Level == CertificateModel::NodeType::CERTIFICATE && (!node->m_IsLoaded)) - node->m_fLoader(); - return node->m_lChildren.size(); - } -} - -Qt::ItemFlags CertificateModel::flags( const QModelIndex& index) const -{ - return Qt::ItemIsEnabled | (index.column()==static_cast<int>(Columns::VALUE)?Qt::ItemIsEditable:Qt::NoItemFlags); -} - -int CertificateModel::columnCount( const QModelIndex& parent) const -{ - Q_UNUSED(parent) - return 2; -} - -QModelIndex CertificateModel::parent( const QModelIndex& index) const -{ - if (!index.isValid()) - return QModelIndex(); - - const CertificateNode* node = static_cast<CertificateNode*>(index.internalPointer()); - - return node->m_pParent ? createIndex(node->m_pParent->m_Index, index.column(), node->m_pParent) : QModelIndex(); -} - -QModelIndex CertificateModel::index( int row, int column, const QModelIndex& parent) const -{ - if((!parent.isValid()) && row >= 0 && row < d_ptr->m_lTopLevelNodes.size() && column < 2) - return createIndex( row, column, d_ptr->m_lTopLevelNodes[row]); - else if (parent.isValid() && row >= 0) { - const CertificateNode* node = static_cast<CertificateNode*>(parent.internalPointer()); - if (node->m_lChildren.size() > row) - return createIndex( row , column, node->m_lChildren[row]); - } - return QModelIndex(); -} - -QVariant CertificateModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - Q_UNUSED(section) - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return QObject::tr("Header"); - - return QVariant(); -} - -/** - *Create a certificate. It will later be registerer in the daemon - * - * @note The path has to be a file, but can contain multiple certificates - */ -Certificate* CertificateModel::getCertificateFromPath(const QString& path, Account* a) -{ - if (!a) - return getCertificateFromPath(path,Certificate::Type::CALL); - - CertificateNode* cat = d_ptr->getCategory(a); - - Certificate* cert = d_ptr->m_hCertificates.value(path); - - if (!cert) { - cert = new Certificate(path, Certificate::Type::NONE); - - { // mutex - QMutexLocker(&d_ptr->m_CertInsertion); - d_ptr->m_hCertificates[path.toLatin1()] = cert; - } // mutex - - //Add it to the model - d_ptr->addToTree(cert,a); - } - - CertificateNode* node = d_ptr->m_hNodes.value(cert); - - if (node) { - if (node->m_pParent != cat) { - CertificateNode* node2 = d_ptr->addToTree(cert,cat); - node->m_hSiblings[a] = node2; - } - } - return cert; -} - -Certificate* CertificateModel::getCertificateFromPath(const QString& path, Certificate::Type type) -{ - const QString id = path; - - Certificate* cert = d_ptr->m_hCertificates.value(id); - - //The certificate is not loaded yet - if (!cert) { - cert = new Certificate(path, type); - - { // mutex - QMutexLocker(&d_ptr->m_CertInsertion); - d_ptr->m_hCertificates[path.toLatin1()] = cert; - } // mutex - - //Add it to the model - d_ptr->addToTree(cert); - } - - return cert; -} - -Certificate* CertificateModel::getCertificateFromId(const QString& id, Account* a, const QString& category) -{ - Certificate* cert = d_ptr->m_hCertificates.value(id); - - //The certificate is not loaded yet - if (!cert) { - cert = new Certificate(id); - - { // mutex - QMutexLocker(&d_ptr->m_CertInsertion); - d_ptr->m_hCertificates[id.toLatin1()] = cert; - } // mutex - - if ((!a) && (!category.isEmpty())) { - CertificateNode* cat = d_ptr->m_hStrToCat.value(category); - - if (!cat) { - cat = d_ptr->createCategory(category, a?QString("%1 certificates").arg(a->alias()):QString(), QString()); - } - - d_ptr->addToTree(cert,cat); - } - else { - //Add it to the model - d_ptr->addToTree(cert, a); - } - } - - return cert; -} - -CertificateProxyModel::CertificateProxyModel(CertificateModel* parent, CertificateNode* root) : QAbstractProxyModel(parent),m_pRoot(root) -{ - //For debugging - switch (root->m_Level) { - case CertificateModel::NodeType::CERTIFICATE : - setObjectName(root->m_pCertificate->path()); - break; - case CertificateModel::NodeType::DETAILS_CATEGORY: - setObjectName(root->m_pParent->m_pCertificate->path()); - break; - case CertificateModel::NodeType::DETAILS : - setObjectName(root->m_pParent->m_pParent->m_pCertificate->path()); - break; - case CertificateModel::NodeType::CATEGORY : - break; - } - setSourceModel(parent); -} - -QModelIndex CertificateProxyModel::mapFromSource(const QModelIndex& sourceIndex) const -{ - if (!sourceIndex.isValid()) - return QModelIndex(); - CertificateModel::NodeType type = qvariant_cast<CertificateModel::NodeType>(sourceIndex.data((int)CertificateModel::Role::NodeType)); - switch (type) { - case CertificateModel::NodeType::CATEGORY : - case CertificateModel::NodeType::CERTIFICATE : - return QModelIndex(); - case CertificateModel::NodeType::DETAILS_CATEGORY: - case CertificateModel::NodeType::DETAILS : - return createIndex(sourceIndex.row(),sourceIndex.column(),sourceIndex.internalPointer()); - } - return QModelIndex(); -} - -QModelIndex CertificateProxyModel::mapToSource(const QModelIndex& proxyIndex) const -{ - return CertificateModel::instance().d_ptr->createIndex(proxyIndex.row(),proxyIndex.column(),proxyIndex.internalPointer()); -} - -QModelIndex CertificateProxyModel::index( int row, int column, const QModelIndex& parent) const -{ - if ((parent.isValid() && parent.model() != this) || column > 1) - return QModelIndex(); - - CertificateNode* node = parent.isValid()?static_cast<CertificateNode*>(parent.internalPointer()):m_pRoot; - - if ((!node) || row >= node->m_lChildren.size()) - return QModelIndex(); - - return createIndex(row, column, node->m_lChildren[row]); -} - -QModelIndex CertificateProxyModel::parent( const QModelIndex& index ) const -{ - if ((index.model() != this) || (!index.isValid())) - return QModelIndex(); - - CertificateNode* node = static_cast<CertificateNode*>(index.internalPointer()); - - if (!node) - return QModelIndex(); - - return (node->m_pParent == m_pRoot)?QModelIndex() : createIndex(node->m_pParent->m_Index, index.column(), node->m_pParent); -} - -int CertificateProxyModel::rowCount( const QModelIndex& parent ) const -{ - return parent.isValid()? sourceModel()->rowCount(mapToSource(parent)) : m_pRoot->m_lChildren.size(); -} - -int CertificateProxyModel::columnCount( const QModelIndex& parent ) const -{ - return sourceModel()->columnCount(mapToSource(parent)); -} - -QAbstractItemModel* CertificateModelPrivate::getModelCommon(CertificateNode* node) -{ - if (node) { - if (node->m_Level == CertificateModel::NodeType::CERTIFICATE && (!node->m_IsLoaded)) - node->m_fLoader(); - - CertificateProxyModel* m = new CertificateProxyModel(q_ptr,node); - - return m; - } - - return nullptr; -} - -/** - * This model is a proxy of CertificateModel with only the current certificate - * - * Please note that the object ownership will be transferred. To avoid memory - * leaks, the users of this object must delete it once they are done with it. - */ -QAbstractItemModel* CertificateModelPrivate::model(const Certificate* cert) const -{ - if (!cert) - return nullptr; - return const_cast<CertificateModelPrivate*>(this)->getModelCommon(m_hNodes.value(cert)); -} - -/** - * Return the list of security checks performed on the certificate as a model - */ -QAbstractItemModel* CertificateModelPrivate::checksModel(const Certificate* cert) const -{ - if (!cert) - return nullptr; - - CertificateNode* node = m_hNodes.value(cert); - - if (!node) - return nullptr; - - if (node->m_Level == CertificateModel::NodeType::CERTIFICATE && (!node->m_IsLoaded)) - node->m_fLoader(); - - if (node->m_lChildren.size() < 2) - return nullptr; - - return const_cast<CertificateModelPrivate*>(this)->getModelCommon(node->m_lChildren[1]); -} - -/** - * This model is a proxy of CertificateModel with only the current certificate - * - * @param idx An index from a CertificateModel or one of its proxies - * - * Please note that the object ownership will be transferred. To avoid memory - * leaks, the users of this object must delete it once they are done with it. - */ -QAbstractItemModel* CertificateModel::singleCertificateModel(const QModelIndex& idx) const -{ - if ((!idx.isValid())) - return nullptr; - - QModelIndex index = idx; - while(index.model() != this) { - QAbstractProxyModel* m = qobject_cast<QAbstractProxyModel*>(const_cast<QAbstractItemModel*>(idx.model())); - if (!m) - break; - - index = m->mapToSource(index); - } - - if ((!index.isValid())) - return nullptr; - - CertificateNode* node = static_cast<CertificateNode*>(idx.internalPointer()); - return d_ptr->getModelCommon(node); -} - -/** - * Create a view of the CertificateModel with only the certificates - * associated with an account. This doesn't contain the account - * own certificates. - */ -QAbstractItemModel* CertificateModelPrivate::createKnownList(const Account* a) const -{ - CertificateNode* cat = const_cast<CertificateModelPrivate*>(this)->getCategory(a); - return new CertificateProxyModel(const_cast<CertificateModel*>(q_ptr),cat); -} - -QAbstractItemModel* CertificateModelPrivate::createBannedList(const Account* a) const -{ - QAbstractItemModel* m = m_hAccBan.value(a); - - if (m) - return m; - - CertificateNode* cat = const_cast<CertificateModelPrivate*>(this)->createCategory(a->id()+"_"+DRing::Certificate::Status::BANNED,QString(),QString()); - - m = new CertificateProxyModel(const_cast<CertificateModel*>(q_ptr),cat); - - m_hAccBan[a] = m; - m_hAccBanCat[a] = cat; - - return m; -} - -QAbstractItemModel* CertificateModelPrivate::createAllowedList(const Account* a) const -{ - QAbstractItemModel* m = m_hAccAllow.value(a); - - if (m) - return m; - - CertificateNode* cat = const_cast<CertificateModelPrivate*>(this)->createCategory(a->id()+"_"+DRing::Certificate::Status::ALLOWED,QString(),QString()); - - m = new CertificateProxyModel(const_cast<CertificateModel*>(q_ptr),cat); - - m_hAccAllow[a] = m; - m_hAccAllowCat[a] = cat; - - return m; -} - -bool CertificateModelPrivate::allowCertificate(Certificate* c, Account* a) -{ - if ((!a) || (!c)) - return false; - - //Make sure the lists exist - createAllowedList(a); - createBannedList(a); - - CertificateNode* allow = m_hAccAllowCat .value( a ); - CertificateNode* ban = m_hAccBanCat .value( a ); - CertificateNode* sibling = m_hNodes .value( c ); - - //Check if it's already there - if (isPartOf(sibling, allow)) - return true; - - //Notify the daemon - ConfigurationManager::instance().setCertificateStatus( - a->id (), - c->remoteId(), - DRing::Certificate::Status::ALLOWED - ); - - //Check if the certificate isn't banned - if (isPartOf(sibling, ban)) - removeFromTree(c, ban); - - //Add it - addToTree(c, allow); - - return true; -} - -/** - * Ban a certificate - * @warning This method have a O(N) complexity where N is the number of - * allowed certificate for account a - */ -bool CertificateModelPrivate::banCertificate(Certificate* c, Account* a) -{ - if ((!a) || (!c)) - return false; - - //Make sure the lists exist - createAllowedList(a); - createBannedList(a); - - CertificateNode* allow = m_hAccAllowCat .value( a ); - CertificateNode* ban = m_hAccBanCat .value( a ); - CertificateNode* sibling = m_hNodes .value( c ); - - //Check if it's already there - if (isPartOf(sibling, ban)) - return true; - - //Notify the daemon - ConfigurationManager::instance().setCertificateStatus( - a->id (), - c->remoteId(), - DRing::Certificate::Status::BANNED - ); - - //Check if the certificate isn't allowed - if (isPartOf(sibling, allow)) - removeFromTree(c, allow); - - //Add it - addToTree(c, ban); - - return true; -} - -void CertificateModelPrivate::slotCertificateStateChanged(const QString& accountId, const QString& certId, const QString& state) -{ - if( auto a = AccountModel::instance().getById(accountId.toLatin1())) { - auto c = q_ptr->getCertificateFromId(certId, a); - - //Make sure the lists exist - createAllowedList(a); - createBannedList(a); - - CertificateNode* allow = m_hAccAllowCat.value(a); - CertificateNode* ban = m_hAccBanCat.value(a) ; - CertificateNode* sibling = m_hNodes.value(c); - - if (state == DRing::Certificate::Status::ALLOWED) { - //Remove it from the ban list - if (isPartOf(sibling, ban)) - removeFromTree(c, ban); - - //Add it to the allow list - if (not isPartOf(sibling, allow) ) - addToTree(c, allow); - } else if (state == DRing::Certificate::Status::BANNED) { - //Remove it from the allow list - if (isPartOf(sibling, allow)) - removeFromTree(c, allow); - - //Add it to the ban list - if (not isPartOf(sibling, ban) ) - addToTree(c, ban); - } else if (state == DRing::Certificate::Status::UNDEFINED) { - //should not happen - qWarning() << "certificate status changed to UNDEFINED" << certId << "for account" << accountId; - } else { - //should not happen either - qWarning() << "unknown certificate status" << certId << state << "for account" << accountId; - } - } else { - qWarning() << "certificate status changed for unknown account" << accountId << certId; - } -} - -void CertificateModel::collectionAddedCallback(CollectionInterface* collection) -{ - Q_UNUSED(collection) -} - -bool CertificateModel::addItemCallback(const Certificate* item) -{ - Q_UNUSED(item) - return false; -} - -bool CertificateModel::removeItemCallback(const Certificate* item) -{ - Q_UNUSED(item) - return false; -} - - -#include <certificatemodel.moc> diff --git a/src/certificatemodel.h b/src/certificatemodel.h deleted file mode 100644 index dca26b2be69d8feca6f132ab644d21a94e11f99d..0000000000000000000000000000000000000000 --- a/src/certificatemodel.h +++ /dev/null @@ -1,100 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractItemModel> -#include "typedefs.h" - -#include "certificate.h" -#include "itemdataroles.h" - -class Account; - -class CertificateModelPrivate; - -class LIB_EXPORT CertificateModel : public QAbstractItemModel, public CollectionManagerInterface<Certificate> -{ - Q_OBJECT -public: - friend class CertificateProxyModel; - friend struct CertificateNode; - friend class Certificate; - friend class CertificatePrivate; - friend class Account; - - enum class Role { - NodeType = static_cast<int>(Ring::Role::UserRole) + 100, - isDetail , - isCheck , - detail , - check , - requirePrivateKey , - - // "Virtual" roles for each certificate values - DetailRoleBase = 1000, - }; - - enum class Columns { - NAME = 0, - VALUE = 1, - }; - - enum class NodeType { - CATEGORY = 0, - CERTIFICATE = 1, - DETAILS_CATEGORY = 2, - DETAILS = 3, - }; - - //Constructor - explicit CertificateModel(QObject* parent = nullptr); - virtual ~CertificateModel(); - - //Model implementation - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QVariant headerData ( int section, Qt::Orientation, int role = Qt::DisplayRole ) const override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getter - QAbstractItemModel* singleCertificateModel(const QModelIndex& idx) const; - - //Mutator - Certificate* getCertificateFromPath(const QString& path, Certificate::Type type = Certificate::Type::NONE); - Certificate* getCertificateFromPath(const QString& path, Account* a); - Certificate* getCertificateFromId(const QString& id, Account* a = nullptr, const QString& category = QString()); - - //Singleton - static CertificateModel& instance(); - -private: - - //Backend interface - virtual void collectionAddedCallback(CollectionInterface* collection) override; - virtual bool addItemCallback(const Certificate* item) override; - virtual bool removeItemCallback(const Certificate* item) override; - - CertificateModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(CertificateModel) -}; -Q_DECLARE_METATYPE(CertificateModel::NodeType) diff --git a/src/chainoftrustmodel.cpp b/src/chainoftrustmodel.cpp deleted file mode 100644 index 3084ab01708eb7d039e47cb5e19903f93f49de4a..0000000000000000000000000000000000000000 --- a/src/chainoftrustmodel.cpp +++ /dev/null @@ -1,176 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "chainoftrustmodel.h" - -#include <certificate.h> -#include <extensions/securityevaluationextension.h> -#include <securityevaluationmodel.h> - -struct ChainedCertificateNode -{ - ChainedCertificateNode(Certificate* c) : m_pCertificate(c),m_pParent(nullptr),m_pChild(nullptr){} - Certificate* m_pCertificate; - ChainedCertificateNode* m_pParent; - ChainedCertificateNode* m_pChild; -}; - -class ChainOfTrustModelPrivate -{ -public: - Certificate* m_pCertificate; - ChainedCertificateNode* m_pRoot; -}; - -ChainOfTrustModel::ChainOfTrustModel(Certificate* c) : QAbstractItemModel(c), d_ptr(new ChainOfTrustModelPrivate()) -{ - d_ptr->m_pCertificate = c; - - ChainedCertificateNode* n = nullptr; - - Certificate* cn = c; - - while (cn) { - ChainedCertificateNode* prev = n; - - n = new ChainedCertificateNode(cn); - n ->m_pChild = prev ; - - if (prev) - prev->m_pParent = n ; - - Certificate* next = cn->signedBy(); - - //Prevent infinite loop of self signed certificates - cn = next == cn ? nullptr : next; - } - - d_ptr->m_pRoot = n; - - emit layoutChanged(); -} - -ChainOfTrustModel::~ChainOfTrustModel() -{ - delete d_ptr; -} - -QHash<int,QByteArray> ChainOfTrustModel::roleNames() const -{ - static QHash<int,QByteArray> roles; - - if (roles.isEmpty()) { - roles[(int) Role::OBJECT] = "object"; - } - - return roles; -} - -QVariant ChainOfTrustModel::data( const QModelIndex& index, int role ) const -{ - if (!index.isValid()) - return QVariant(); - - ChainedCertificateNode* c = static_cast<ChainedCertificateNode*>(index.internalPointer()); - - switch(role) { - case Qt::DisplayRole: - return c->m_pCertificate->publicKeyId(); - case Qt::DecorationRole: - if (c->m_pCertificate->extension<SecurityEvaluationExtension>()) { - return c->m_pCertificate->extension<SecurityEvaluationExtension>()->securityLevelIcon(c->m_pCertificate); - } - break; - case (int) Role::OBJECT: - return QVariant::fromValue(c->m_pCertificate); - case (int) Role::SECURITY_LEVEL: - if (c->m_pCertificate->extension<SecurityEvaluationExtension>()) { - return QVariant::fromValue( - c->m_pCertificate->extension<SecurityEvaluationExtension>()->securityLevel(c->m_pCertificate) - ); - } - break; - } - - return QVariant(); -} - -bool ChainOfTrustModel::setData( const QModelIndex& index, const QVariant &value, int role ) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role ) - - return false; -} - -int ChainOfTrustModel::rowCount( const QModelIndex& parent ) const -{ - if (!parent.isValid()) - return 1; - - ChainedCertificateNode* c = static_cast<ChainedCertificateNode*>(parent.internalPointer()); - - //The last node is the "leaf" certificate that is being viewed - return c->m_pChild ? 1 : 0; -} - -Qt::ItemFlags ChainOfTrustModel::flags( const QModelIndex& index ) const -{ - return index.isValid() ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags; -} - -int ChainOfTrustModel::columnCount( const QModelIndex& parent ) const -{ - Q_UNUSED(parent) - return 1; -} - -QModelIndex ChainOfTrustModel::parent( const QModelIndex& idx ) const -{ - if (!idx.isValid()) - return QModelIndex(); - - ChainedCertificateNode* c = static_cast<ChainedCertificateNode*>(idx.internalPointer()); - - //Root - if (!c->m_pParent) - return QModelIndex(); - - return createIndex(0,0,c->m_pParent); -} - -QModelIndex ChainOfTrustModel::index( int row, int column, const QModelIndex& parent ) const -{ - if (row || column) - return QModelIndex(); - - if (!parent.isValid()) - return createIndex(0,0,d_ptr->m_pRoot); - - ChainedCertificateNode* c = static_cast<ChainedCertificateNode*>(parent.internalPointer()); - - return createIndex(0,0,c->m_pChild); -} - -QVariant ChainOfTrustModel::headerData( int section, Qt::Orientation o, int role ) const -{ - if ((!section) && role == Qt::DisplayRole && o == Qt::Horizontal) - return tr("Chain of trust"); - - return QVariant(); -} \ No newline at end of file diff --git a/src/chainoftrustmodel.h b/src/chainoftrustmodel.h deleted file mode 100644 index 4e80958777150f2726b5a665f9c5edb7763994c7..0000000000000000000000000000000000000000 --- a/src/chainoftrustmodel.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractItemModel> -#include <typedefs.h> - -class ChainOfTrustModelPrivate; -class Certificate; - -class LIB_EXPORT ChainOfTrustModel : public QAbstractItemModel -{ - Q_OBJECT - - friend class Certificate; -public: - - enum class Role { - OBJECT = Qt::UserRole+1, - SECURITY_LEVEL, - }; - - //Model implementation - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QVariant headerData ( int section, Qt::Orientation, int role = Qt::DisplayRole ) const override; - virtual QHash<int,QByteArray> roleNames() const override; - -private: - explicit ChainOfTrustModel(Certificate* c); - virtual ~ChainOfTrustModel(); - - ChainOfTrustModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(ChainOfTrustModel) -}; - diff --git a/src/collectionconfigurationinterface.h b/src/collectionconfigurationinterface.h deleted file mode 100644 index b71ba8f1bfebe34c73b154107dd1d23a9999592a..0000000000000000000000000000000000000000 --- a/src/collectionconfigurationinterface.h +++ /dev/null @@ -1,56 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#include "typedefs.h" - -class CollectionInterface; - -class LIB_EXPORT CollectionConfigurationInterface : public QObject -{ - Q_OBJECT -public: - - explicit CollectionConfigurationInterface(QObject* parent = nullptr) : QObject(parent) {} - - //Getter - virtual QByteArray id () const = 0; - virtual QString name() const = 0; - virtual QVariant icon() const = 0; - - //Mutator - - /** - * This function will be called when a collection request to be configured - * - * @param col The collection to be edited. It can casted - * @param parent can be used for layout information. - */ - virtual void loadCollection(CollectionInterface* col, QObject* parent = nullptr) =0; - - virtual void save(){} - virtual bool hasChanged() {return false;} - -Q_SIGNALS: - void changed(); - -}; -Q_DECLARE_METATYPE(CollectionConfigurationInterface*) - diff --git a/src/collectioncreationinterface.h b/src/collectioncreationinterface.h deleted file mode 100644 index fb0e7fbc3d6c19c33b6e0f2dd4e923004d97993a..0000000000000000000000000000000000000000 --- a/src/collectioncreationinterface.h +++ /dev/null @@ -1,33 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#include "typedefs.h" -class LIB_EXPORT CollectionCreationInterface : public QObject -{ - Q_OBJECT -public: - virtual QByteArray id () const = 0; - virtual QString name() const = 0; - virtual QVariant icon() const = 0; -}; - -Q_DECLARE_METATYPE(CollectionCreationInterface*) - diff --git a/src/collectioneditor.cpp b/src/collectioneditor.cpp deleted file mode 100644 index 51b0cfd1fa92eee4a4a3cac00c1896b735f84272..0000000000000000000000000000000000000000 --- a/src/collectioneditor.cpp +++ /dev/null @@ -1,27 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "collectioneditor.h" - -CollectionEditorBase::CollectionEditorBase(QAbstractItemModel* m) : m_pModel(m), -d_ptr(nullptr) -{} - -QAbstractItemModel* CollectionEditorBase::model() const -{ - return m_pModel; -} diff --git a/src/collectioneditor.h b/src/collectioneditor.h deleted file mode 100644 index 524548eb3a860a087cacb8dfb09c16006b9a8bb5..0000000000000000000000000000000000000000 --- a/src/collectioneditor.h +++ /dev/null @@ -1,99 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractItemModel> - -#include <typedefs.h> - -//Ring -class ContactMethod; -class CollectionEditorBasePrivate; - -class LIB_EXPORT CollectionEditorBase -{ -public: - explicit CollectionEditorBase(QAbstractItemModel* m); - QAbstractItemModel* model() const; - -protected: - QAbstractItemModel* m_pModel; - -private: - CollectionEditorBasePrivate* d_ptr; - Q_DECLARE_PRIVATE(CollectionEditorBase) -}; - -template<typename T> class CollectionMediator; - -/** - * This is the class that does the actual work. This class - * represent a delegate of CollectionInterface. It is usually - * recommended to implement this as a private class in the .cpp - * that implement the CollectionInterface. - * - * The rational behind this inversion of responsibility layer - * is to avoid using a template class for CollectionInterface. - * This would add obstable when implementing objects using it due - * to C++11 lack of generic template polymorphism. A base class - * extended by the template call also doesn't solve those issues. - */ -template<typename T> -class LIB_EXPORT CollectionEditor : public CollectionEditorBase { - friend class CollectionInterface; -public: - explicit CollectionEditor(CollectionMediator<T>* m); - virtual ~CollectionEditor(); - - CollectionMediator<T>* mediator() const; - - virtual bool save(const T* item) =0; - virtual bool batchSave(const QList<T*> contacts); - virtual bool batchRemove(const QList<T*> contacts); - virtual bool remove(const T* item); - - ///Edit 'item', the implementation may be a GUI or something else - virtual bool edit ( T* item ); - - ///Add a new item to the backend - virtual bool addNew (T* item ) = 0; - - ///Add an existing item to the collection - virtual bool addExisting(const T* item ) = 0; - - ///Add a new phone number to an existing item - virtual bool addContactMethod( T* item , ContactMethod* number ); - -private: - /** - * Return the items generated by this backend. This overloaded - * version also make sure that the type is compatible. - */ - virtual QVector<T*> items() const = 0; - - /** - * Return the metatype of this editor - */ - QMetaObject metaObject(); - - //Attributes - CollectionMediator<T>* m_pMediator; -}; - -#include "collectioneditor.hpp" - diff --git a/src/collectioneditor.hpp b/src/collectioneditor.hpp deleted file mode 100644 index 1f4062780388ec64ace208f21d2eabacf88dc2e8..0000000000000000000000000000000000000000 --- a/src/collectioneditor.hpp +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -//Qt -#include <QtCore/QMetaObject> - -//Ring -#include <collectionmediator.h> - -template<typename T> -CollectionEditor<T>::CollectionEditor(CollectionMediator<T>* m) : CollectionEditorBase(m->model()), m_pMediator(m) -{ - Q_ASSERT(m); -} - -template<typename T> -CollectionEditor<T>::~CollectionEditor() -{ - -} - -template<typename T> -CollectionMediator<T>* CollectionEditor<T>::mediator() const -{ - return m_pMediator; -} - -template<typename T> -QMetaObject metaObject() -{ - return T::staticMetaObject(); -} - -///Default batch saving implementation, some collections have better APIs -template <class T> bool CollectionEditor<T>::batchSave(const QList<T*> contacts) -{ - bool ret = true; - for(const T* c : contacts) { - ret &= save(c); - } - return ret; -} - -///Default batch saving implementation, some collections have better APIs -template <class T> bool CollectionEditor<T>::batchRemove(const QList<T*> contacts) -{ - bool ret = true; - for(const T* c : contacts) { - ret &= remove(c); - } - return ret; -} - -template <class T> -bool CollectionEditor<T>::addContactMethod( T* item , ContactMethod* number ) -{ - Q_UNUSED(item) - Q_UNUSED(number) - return false; -} - -template <class T> -bool CollectionEditor<T>::remove(const T* item) -{ - Q_UNUSED(item) - return false; -} - -template <class T> -bool CollectionEditor<T>::edit(T* item) -{ - Q_UNUSED(item) - return false; -} diff --git a/src/collectionextensioninterface.cpp b/src/collectionextensioninterface.cpp deleted file mode 100644 index df62842c04fbd106ffd9822f0e8f0127f83df98f..0000000000000000000000000000000000000000 --- a/src/collectionextensioninterface.cpp +++ /dev/null @@ -1,24 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "collectionextensioninterface.h" - - -CollectionExtensionInterface::CollectionExtensionInterface(QObject* parent) : QObject(parent) -{ - -} diff --git a/src/collectionextensioninterface.h b/src/collectionextensioninterface.h deleted file mode 100644 index a02a218f68f1690bbcfc6b1d8c28f02d838e4a79..0000000000000000000000000000000000000000 --- a/src/collectionextensioninterface.h +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" - -#include <QtCore/QVariant> -#include <QtCore/QModelIndex> - -class ItemBase; -class CollectionInterface; - -/** - * This interface can be used to extend the collection system. - * - * It is a business logic container. The interface will eventually be extended - * to allow various callbacks at key ItemBase lifecycle moment. - * - * Subclasses need to call DECLARE_COLLECTION_EXTENSION in the .cpp and - * include collectionextensionmodel.h - */ -class LIB_EXPORT CollectionExtensionInterface : public QObject -{ - Q_OBJECT - - friend class CollectionExtensionModel; - -public: - - explicit CollectionExtensionInterface(QObject* parent); - - virtual QVariant data(int role) const = 0; - -Q_SIGNALS: - void dataChanged(const QModelIndex& idx); -}; - -#define DECLARE_COLLECTION_EXTENSION_M1(x, y) x ## y -#define DECLARE_COLLECTION_EXTENSION_M2(x, y) DECLARE_COLLECTION_EXTENSION_M1(x, y) - -#define DECLARE_COLLECTION_EXTENSION(T) __attribute__ ((unused)) \ -static auto DECLARE_COLLECTION_EXTENSION_M2(val,__COUNTER__) = []{\ - CollectionExtensionModel::registerExtension<T>();\ - return 0;\ -}(); - diff --git a/src/collectionextensionmodel.cpp b/src/collectionextensionmodel.cpp deleted file mode 100644 index c67d90073edbd1858ca553ca490718a4f4f77689..0000000000000000000000000000000000000000 --- a/src/collectionextensionmodel.cpp +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "collectionextensionmodel.h" - -#include "collectionextensioninterface.h" - -class CollectionExtensionModelPrivate -{ -}; - -CollectionExtensionModel::~CollectionExtensionModel() -{ - delete d_ptr; -} - -QList<CollectionExtensionInterface*>& CollectionExtensionModelSpecific::entries() -{ - static QList<CollectionExtensionInterface*> m_slEntries; - - return m_slEntries; -} - -CollectionExtensionModel& CollectionExtensionModel::instance() -{ - static auto instance = new CollectionExtensionModel; - return *instance; -} - -QVariant CollectionExtensionModel::data( const QModelIndex& index, int role ) const -{ - if (!index.isValid()) - return QVariant(); - - return CollectionExtensionModelSpecific::entries()[index.row()]->data(role); -} - -int CollectionExtensionModel::rowCount( const QModelIndex& parent) const -{ - return parent.isValid() ? 0 : CollectionExtensionModelSpecific::entries().size(); -} - -Qt::ItemFlags CollectionExtensionModel::flags( const QModelIndex& index) const -{ - return index.isValid() ? Qt::ItemIsEnabled : Qt::NoItemFlags; -} - -bool CollectionExtensionModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QHash<int,QByteArray> CollectionExtensionModel::roleNames() const -{ - return {}; -} diff --git a/src/collectionextensionmodel.h b/src/collectionextensionmodel.h deleted file mode 100644 index 1ddf859ff5002eb4a873a7492b2e1ceb6e4ef943..0000000000000000000000000000000000000000 --- a/src/collectionextensionmodel.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> - -#include <typedefs.h> - -class CollectionExtensionInterface; - -class CollectionExtensionModelPrivate; - -/** - * This model expose the collections available to the managers - */ -class LIB_EXPORT CollectionExtensionModel : public QAbstractListModel -{ - Q_OBJECT - -public: - - //Model functions - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - /** - * Register an extension available to all type of collections - * - * This does **NOT** activate the extension - */ - template<class T> - static int registerExtension(); - - /** - * Return an unique identifier for that extension type - */ - template<class T> - static int getExtensionId(); - - /** - * Get the instance of a particular extension - * - * This function will register the type if it isn't already registered - */ - template<class T> - static T* getExtension(); - - //Singleton - static CollectionExtensionModel& instance(); - - -private: - virtual ~CollectionExtensionModel(); - - CollectionExtensionModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(CollectionExtensionModel) -}; - -#include <collectionextensionmodel.hpp> - diff --git a/src/collectionextensionmodel.hpp b/src/collectionextensionmodel.hpp deleted file mode 100644 index 3198e0d2a8d1b913df32d9996a32510b1e655829..0000000000000000000000000000000000000000 --- a/src/collectionextensionmodel.hpp +++ /dev/null @@ -1,50 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - - -class CollectionExtensionModelSpecific -{ -public: - static QList<CollectionExtensionInterface*>& entries(); -}; - -template<class T> -int CollectionExtensionModel::registerExtension() -{ - static bool typeInit = false; - - static int typeId = CollectionExtensionModelSpecific::entries().size(); - - if (!typeInit) { - CollectionExtensionModelSpecific::entries() << new T(&CollectionExtensionModel::instance()); - } - - return typeId; -} - -template<class T> -int CollectionExtensionModel::getExtensionId() -{ - return registerExtension<T>(); -} - -template<class T> -T* CollectionExtensionModel::getExtension() -{ - return (T*)CollectionExtensionModelSpecific::entries()[registerExtension<T>()]; -} diff --git a/src/collectioninterface.cpp b/src/collectioninterface.cpp deleted file mode 100644 index c8f233ecc0c6a812b43d4a793977ef1ee6365d96..0000000000000000000000000000000000000000 --- a/src/collectioninterface.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/************************************************************************************ - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***********************************************************************************/ - -//Parent -#include "collectioninterface.h" - -//Ring library -#include "person.h" -#include "call.h" -#include "contactmethod.h" -#include "collectioneditor.h" -#include "collectionextensionmodel.h" -#include "itembase.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" - -//Libstdc++ -#include <functional> - -//Qt -#include <QtCore/QHash> -#include <QtCore/QDebug> -#include <QtCore/QIdentityProxyModel> -#include <QtCore/QCoreApplication> - -class EnabledExtensionsProxy final : public QIdentityProxyModel -{ - Q_OBJECT - -public: - EnabledExtensionsProxy(QAbstractItemModel* parent); - - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant& value,int role ) override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - -private: - QHash<int,bool> m_Disabled; -}; - -class CollectionInterfacePrivate -{ -public: - explicit CollectionInterfacePrivate(); - - //Attributes - EnabledExtensionsProxy* m_pEnabledExtensions; -}; - -EnabledExtensionsProxy::EnabledExtensionsProxy(QAbstractItemModel* parent) : QIdentityProxyModel(parent) -{ - setSourceModel(parent); -} - -CollectionInterfacePrivate::CollectionInterfacePrivate(): m_pEnabledExtensions(nullptr) -{ -} - -void CollectionInterface::init() -{ - d_ptr2 = new CollectionInterfacePrivate(); -} - -///Destructor -CollectionInterface::~CollectionInterface() -{ - d_ptr->m_fDestruct(); - delete d_ptr2; - delete d_ptr; -} - -QVariant EnabledExtensionsProxy::data( const QModelIndex& index, int role) const -{ - - if (index.isValid() && role == Qt::CheckStateRole) - return m_Disabled[index.row()] ? Qt::Unchecked : Qt::Checked; - - return QIdentityProxyModel::data(index,role); -} - -bool EnabledExtensionsProxy::setData( const QModelIndex& index, const QVariant& value,int role ) -{ - if (index.isValid() && role == Qt::CheckStateRole) { - m_Disabled[index.row()] = value == Qt::Unchecked; - return true; - } - - return false; -} - -Qt::ItemFlags EnabledExtensionsProxy::flags( const QModelIndex& index) const -{ - return QIdentityProxyModel::flags(index) | Qt::ItemIsUserCheckable; -} - -QAbstractItemModel* CollectionInterface::extensionsModel() const -{ - if (!d_ptr2->m_pEnabledExtensions) - d_ptr2->m_pEnabledExtensions = new EnabledExtensionsProxy(&CollectionExtensionModel::instance()); - return d_ptr2->m_pEnabledExtensions; -} - -CollectionInterface* CollectionInterface::parent () const -{ - return d_ptr->m_pParent; -} - -QVector<CollectionInterface*> CollectionInterface::children() const -{ - return d_ptr->m_lChildren; -} - -QVariant CollectionInterface::icon() const -{ - return GlobalInstances::pixmapManipulator().collectionIcon(this); -} - -bool CollectionInterface::clear() -{ - return false; -} - -bool CollectionInterface::reload() -{ - return false; -} - -bool CollectionInterface::enable(bool) -{ - return false; -} - -QAbstractItemModel* CollectionInterface::model() const -{ - return static_cast<CollectionEditorBase*>(d_ptr->m_pEditor)->model(); -} - -void CollectionInterface::addChildren(CollectionInterface* c) -{ - d_ptr->m_lChildren << c; -} - - -bool CollectionInterface::add(ItemBase* base) -{ - return d_ptr->m_fAdd(base); -} - -bool CollectionInterface::save(ItemBase* base) -{ - return d_ptr->m_fSave(base); -} - -bool CollectionInterface::save(const ItemBase* base) -{ - return d_ptr->m_fSave(const_cast<ItemBase*>(base)); -} - -bool CollectionInterface::edit(ItemBase* base) -{ - return d_ptr->m_fEdit(base); -} - -bool CollectionInterface::remove(ItemBase* base) -{ - if (d_ptr->m_fRemove(base)) { - deactivate(base); - return true; - } - return false; -} - -int CollectionInterface::size() const -{ - return d_ptr->m_fSize(); -} - -QList<CollectionInterface::Element> CollectionInterface::listId() const -{ - return {}; -} - -bool CollectionInterface::listId(std::function<void(const QList<CollectionInterface::Element>)> callback) const -{ - Q_UNUSED(callback) - return false; -} - -bool CollectionInterface::fetch( const CollectionInterface::Element& element) -{ - Q_UNUSED(element) - return false; -} - -bool CollectionInterface::fetch( const QList<CollectionInterface::Element>& elements) -{ - Q_UNUSED(elements) - return false; -} - -void CollectionInterface::activate(ItemBase* base) -{ - base->d_ptr->m_isActive = true; -} - -void CollectionInterface::deactivate(ItemBase* base) -{ - base->d_ptr->m_isActive = false; -} - -const QMetaObject* CollectionInterface::metaObject() -{ - return &d_ptr->m_pEditorType; -} - -CollectionConfigurationInterface* CollectionInterface::configurator() const -{ - return d_ptr->m_fConfigurator(); -} - -void CollectionInterface::setConfigurator(std::function<CollectionConfigurationInterface*()> getter) -{ - d_ptr->m_fConfigurator = getter; -} - -#include <collectioninterface.moc> diff --git a/src/collectioninterface.h b/src/collectioninterface.h deleted file mode 100644 index 9a6c5d392f2757e075a25212bfb84a0cdf7e1050..0000000000000000000000000000000000000000 --- a/src/collectioninterface.h +++ /dev/null @@ -1,309 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QObject> -#include <QHash> -#include <QStringList> -#include <QVariant> -#include <QtCore/QAbstractItemModel> - -#include "typedefs.h" - -//Libstdc++ -#include <functional> - -//Ring -class CollectionInterfacePrivateT; -class CollectionInterfacePrivate; -class CollectionExtensionInterface; -class CollectionEditorBase; -class CollectionConfigurationInterface; -template<typename T> class CollectionEditor; -template<typename T> class CollectionMediator; -class ItemBase; - -/** - * This is the interface that must be implemented by each item collections to - * be used by a CollectionManager. - * - * The class need to be extended with a template constructor: - * - * MyBackend::MyBackend<Person>(CollectionMediator<Person>* mediator, CollectionInterface* parent = nullptr) : - * CollectionMediator<Person>(mediator,parent) {} - * - * Each collections also need to implement that constructor or they won't load. - */ -class LIB_EXPORT CollectionInterface -{ - template<typename T> friend class CollectionMediator; - template<typename T> friend class CollectionManagerInterface; - friend class CollectionManagerInterfaceBase; - friend class ItemBase; -public: - - /** - * Each backend can have a serie of feaures that are expected to work. While most editor mutators - * are implemented anyway, each backend should list what is officially supposed to work and what is - * not. - */ - enum class SupportedFeatures { - NONE = 0x0 , - LOAD = 0x1 << 0, /*!< Load this backend, DO NOT load anything before "load" is called */ - SAVE = 0x1 << 1, /*!< Save an item */ - EDIT = 0x1 << 2, /*!< Edit, but **DOT NOT**, save an item) */ - PROBE = 0x1 << 3, /*!< Check if the backend has new items (some collections do this automagically)*/ - ADD = 0x1 << 4, /*!< Add (and save) a new item to the backend */ - SAVE_ALL = 0x1 << 5, /*!< Save all items at once, this may or may not be faster than "add" */ - CLEAR = 0x1 << 6, /*!< Clear all items from this backend */ - REMOVE = 0x1 << 7, /*!< Remove a single item */ - EXPORT = 0x1 << 8, /*!< Export all items, format and output need to be defined by each collections */ - IMPORT = 0x1 << 9, /*!< Import items from an external source, details defined by each collections */ - ENABLEABLE = 0x1 << 10, /*!< Can be enabled, I know, it is not a word, but Java use it too */ - DISABLEABLE = 0x1 << 11, /*!< Can be disabled, I know, it is not a word, but Java use it too */ - MANAGEABLE = 0x1 << 12, /*!< Can be managed the config GUI */ - LISTABLE = 0x1 << 13, /*!< List all elements ids from a collection without necessarily loading them */ - RELOAD = 0x1 << 14, /*!< Reload this collection */ - FETCH = 0x1 << 15, /*!< Fetch a single item (when LISTABLE is supported) */ - }; - - typedef QByteArray Element; - - //Generic information getters - - /** - * This method must return an human readable, translatable string. - * This will be used to display the backend in the backend manager - * is SupportedFeatures::MANAGEABLE is set. - */ - virtual QString name () const = 0; - - /** - * Each MANAGEABLE collections can be part of a meta category. This category - * will be the top level element of the BackendManagerModel. This name - * must never change once it is set. - */ - virtual QString category () const = 0; - - /** - * This method must return an optinal icon to be used in the - * backend manager is SupportedFeatures::MANAGEABLE is set. - */ - virtual QVariant icon () const ; - - /** - * Return if the backend is currently enabled. An enabled backend - * is one where items are loaded and operations such as save() - * work (when supported) - */ - virtual bool isEnabled() const = 0; - - /** - * This is the identifier for this backend. This id will not - * be displayed to the user, so it doesn't have to be human - * readable. It is usually useful when linking to remote - * data sources. - */ - virtual QByteArray id () const = 0; - - /** - * Return the features supported by this backend. - * - * This method mush always return the same set of flags. - * - * @see SupportedFeatures - */ - virtual FlagPack<SupportedFeatures> supportedFeatures() const = 0; - - //Management methods - - /** - * Enable this backend, this may or may not imply load() - */ - virtual bool enable (bool); - - /** - * Load a backend. This is used to fetch the elements to - * be added to the model. This function can (and should) - * start external workers to fetch the elements and add - * them asynchroniously. - * - * @see BackendManagerInterface::addItemCallback - * @see BackendManagerInterface::removeItemCallback - */ - virtual bool load ( ) = 0; - - /** - * Reload this backend. In the best case, this should - * update the existing elements instead of deleting them, - * as this will cause a (massive) memory leak. Reloaded - * can be necessary when a file change on disk or by user - * actions. - */ - virtual bool reload ( ); - - /** - * Clear this backend. Please note that the elements themselves - * should *NOT* be deleted as the pointer has been shared with - * upstream. Unless reference counting is implemented everywhere, - * will will cause a crash. - */ - virtual bool clear ( ); - - /** - * Return the number of elements tracked by this collection. - * This can usually be extracted from editor<T>()->items().size(); - */ - virtual int size() const; - - /** - * Return the list of all managed IDs. If the collection support - * SupportedFeatures::LISTABLE. This is the synchronous version, use the - * asynchronous when possible - * - * @warning This method is design to be used by threads, implementation \ - * are responsible to be re-entrant and support multiple concurrent calls - */ - virtual QList<Element> listId() const; - - /** - * Return the list of all managed IDs. If the collection support - * SupportedFeatures::LISTABLE. This is the asynchronious version. - * - * @param callback will be called once the list is ready. - */ - virtual bool listId(std::function<void(const QList<Element>)> callback) const; - - /** - * Fetch an element whose identifier come from "listId". This should be - * implemented in an asynchronous manner. - * - * @param element The element to fetch from the external source - * @return if the request already failed - */ - virtual bool fetch( const Element& element); - - /** - * Same as "bool fetch( const Element& element);", but with multiple items - * - * @param elements A list of ids to be fetched - * - * @see CollectionInterface::fetch - * - * @return false if the request already failed, true otherwise - */ - virtual bool fetch( const QList<Element>& elements); - - /** - * Return a pointer to the model implementing the CollectionManager. - */ - QAbstractItemModel* model() const; - - /** - * Return the items stored in the backend for a given type. The type - * usually is the one managed the CollectionManager. - */ - template<typename T> - QVector<T*> items() const; - - /** - * Some collections can be hierarchical, for example, a email backend - * can have multiple "folders" where mails are stored, a contact backend - * can have multiple contact groups and an history one can have an archived - * section for previous years. This method return the parent when applicable. - */ - CollectionInterface* parent () const; - - /** - * As explained in the "parent()" method, this method return the backend children - * collections. This can be used by a client to implement different behaviour depending - * on the backend at a finer level. - */ - QVector<CollectionInterface*> children() const; - - /** Get the concrete editor associated with this backend. The template arguments - * must match the one used by the model. - */ - template<typename T> - CollectionEditor<T>* editor() const; - - /** - * Add a new element to the backend - */ - bool add (ItemBase* base); - - /** - * Return an object that has been associated with this collection type - * - * It can be set using registerConfigarator() available in every collection - * manager objects such as PersonModel, CategorizedHistoryModel and others. - */ - CollectionConfigurationInterface* configurator() const; - - /** - * Attach or detach an extension to this collection - */ - template<class T> - bool attachExtension(bool enable); - - /** - * Get a model with all available extensions with possibility to activate - * or deactivate them. - */ - QAbstractItemModel* extensionsModel() const; - - /** - * Check if an extension type is active - */ - template<class T> - bool isExtensionActive() const; - - /** - * Get extension "T" - */ - template<class T> - T* extension() const; - -protected: - - //Constructor - template<typename T> - explicit CollectionInterface(CollectionEditor<T>* editor, CollectionInterface* parent = nullptr); - virtual ~CollectionInterface(); - - void setConfigurator(std::function<CollectionConfigurationInterface*()> getter); - void addChildren(CollectionInterface* c); - - bool save (ItemBase* base); - bool save (const ItemBase* base); - bool edit (ItemBase* base); - bool remove (ItemBase* base); - void activate (ItemBase* base); - void deactivate(ItemBase* base); - const QMetaObject* metaObject(); - -private: - CollectionInterfacePrivateT* d_ptr ; - CollectionInterfacePrivate * d_ptr2; - void init(); -}; - -DECLARE_ENUM_FLAGS(CollectionInterface::SupportedFeatures) - -#include <collectioninterface.hpp> - diff --git a/src/collectioninterface.hpp b/src/collectioninterface.hpp deleted file mode 100644 index 75a7250c2712e600c8b97a56094ef4ca91b9d38e..0000000000000000000000000000000000000000 --- a/src/collectioninterface.hpp +++ /dev/null @@ -1,116 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 <collectionextensionmodel.h> - -//TODO don't do this -class ItemBase; - -class CollectionInterfacePrivateT { -public: - CollectionInterfacePrivateT() : m_pParent(nullptr){} - - ///The backend parent of nullptr - CollectionInterface* m_pParent ; - - ///Keep track of all backend childrens - QVector<CollectionInterface*> m_lChildren ; - - ///This need to be casted to a CollectionMediator<T> - void* m_pEditor ; - - ///Use Qt introspection to make sure casting is valid - QMetaObject m_pEditorType; - - std::function<bool(ItemBase*)> m_fAdd ; - std::function<bool(ItemBase*)> m_fSave ; - std::function<bool(ItemBase*)> m_fEdit ; - std::function<bool(ItemBase*)> m_fRemove ; - std::function<int() > m_fSize ; - std::function<void() > m_fDestruct ; - - std::function<CollectionConfigurationInterface*()> m_fConfigurator; -}; - -/** - * The collection from now on take ownership of the editor - */ -template<typename T> -CollectionInterface::CollectionInterface(CollectionEditor<T>* editor, CollectionInterface* parent) : -d_ptr(new CollectionInterfacePrivateT()) -{ - init(); - //Ensure the type is based on QObject (required) - d_ptr->m_pParent = parent; - d_ptr->m_pEditorType = T::staticMetaObject; - d_ptr->m_pEditor = reinterpret_cast<void*>(editor); - - //The cast is safe because the metatype is checked earlier - d_ptr->m_fAdd = [editor](ItemBase* item)->bool { - return editor?editor->addNew(static_cast<T*>(item)) : false; - }; - d_ptr->m_fSave = [editor](ItemBase* item)->bool { - return editor?editor->save(static_cast<T*>(item)) : false; - }; - d_ptr->m_fEdit = [editor](ItemBase* item)->bool { - return editor?editor->edit(static_cast<T*>(item)) : false; - }; - d_ptr->m_fRemove = [editor](ItemBase* item)->bool { - return editor?editor->remove(static_cast<T*>(item)) : false; - }; - d_ptr->m_fSize = [editor]()->int { - return editor?editor->items().size() : 0; - }; - d_ptr->m_fDestruct = [editor]() { - delete editor; - }; -} - -template<typename T> -QVector<T*> CollectionInterface::items() const -{ - const CollectionEditor<T>* e = editor<T>(); - return e?e->items() : QVector<T*>(); -} - -template<typename T> -CollectionEditor<T>* CollectionInterface::editor() const -{ - Q_ASSERT(T::staticMetaObject.className() == d_ptr->m_pEditorType.className()); - return static_cast<CollectionEditor<T>*>(d_ptr->m_pEditor); -} - -template<class T> -bool CollectionInterface::attachExtension(bool enable) -{ - Q_UNUSED(enable); - //FIXME for now all extensions are considered active - return true; -} - -template<class T> -bool CollectionInterface::isExtensionActive() const -{ - return true; -} - -template<class T> -T* CollectionInterface::extension() const -{ - return CollectionExtensionModel::getExtension<T>(); -} diff --git a/src/collectionmanagerinterface.cpp b/src/collectionmanagerinterface.cpp deleted file mode 100644 index 28415a16d68daf32ff68ca2b7f1954b3168a7707..0000000000000000000000000000000000000000 --- a/src/collectionmanagerinterface.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "collectionmanagerinterface.h" - -//Ring -#include <collectionmodel.h> -#include "private/collectionmodel_p.h" - -class CollectionManagerInterfaceBasePrivate -{ -public: - -}; - -void CollectionManagerInterfaceBase::registerToModel(CollectionInterface* col) const -{ - CollectionModel::instance().d_ptr->registerNew(col); -} - -void CollectionManagerInterfaceBase::addCreatorToList(CollectionCreationInterface* creator) -{ - CollectionModel::instance().d_ptr->m_lCreator << creator; -} - -void CollectionManagerInterfaceBase::addConfiguratorToList(CollectionConfigurationInterface* configurator) -{ - CollectionModel::instance().d_ptr->m_lConfigurator << configurator; -} - -void CollectionManagerInterfaceBase::setCollectionConfigurator(CollectionInterface* col, std::function<CollectionConfigurationInterface*()> getter) -{ - col->setConfigurator(getter); -} diff --git a/src/collectionmanagerinterface.h b/src/collectionmanagerinterface.h deleted file mode 100644 index 386104dec08daa5bb57c616a31b5c15f8c61b80d..0000000000000000000000000000000000000000 --- a/src/collectionmanagerinterface.h +++ /dev/null @@ -1,201 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" - -//Qt -#include <QtCore/QString> -#include <QtCore/QMutexLocker> - -//libstdc++ -#include <type_traits> -#include <functional> - -//Ring -#include <collectioninterface.h> -#include <collectionmediator.h> - -class QAbstractItemModel; - -enum LoadOptions { - NONE = 0x0 , - FORCE_ENABLED = 0x1 << 0, - FORCE_DISABLED = 0x1 << 1, -}; - -class CollectionManagerInterfaceBasePrivate; -class CollectionCreationInterface; -class CollectionConfigurationInterface; - -/** - * Common elements for each CollectionManagerInterface - */ -class LIB_EXPORT CollectionManagerInterfaceBase { -public: - virtual ~CollectionManagerInterfaceBase(){} - - virtual bool hasEnabledCollections (FlagPack<CollectionInterface::SupportedFeatures> features = CollectionInterface::SupportedFeatures::NONE) const = 0; - virtual bool hasCollections (FlagPack<CollectionInterface::SupportedFeatures> features = CollectionInterface::SupportedFeatures::NONE) const = 0; - - ///Enable / disable a collection - virtual bool enableCollection( CollectionInterface* collection, bool enabled) = 0; - - virtual bool clearAllCollections() const = 0; - -protected: - void registerToModel(CollectionInterface* col) const; - void addCreatorToList(CollectionCreationInterface* creator); - void addConfiguratorToList(CollectionConfigurationInterface* configurator); - void setCollectionConfigurator(CollectionInterface* col, std::function<CollectionConfigurationInterface*()> getter); - -private: - CollectionManagerInterfaceBasePrivate* d_ptr; - Q_DECLARE_PRIVATE(CollectionManagerInterfaceBase) -}; - -template <class T> -class CollectionManagerInterfacePrivate; - -/** - * This is the base for all models based on the itemcollection framework. - * - * This interface has to be implemented by each models. The abstract - * private methods will be called when the managed collections need - * to interact with the model. - * - * All implementation should define their item collection type in the - * class declaration like: - * - * template <typename T > using CollectionMediator = CollectionMediator<Person>; - * - * And individual collections should extend that alias. For example: - * - * class MyPersonSourceBackend : public CollectionInterface { - * public: - * MyPersonSourceBackend(CollectionInterfaceMediator* mediator) - * }; - * - * The mediator is used to bridge the model and the item collections. The mediator - * implement the common logic that should otherwise have been copy pasted in each - * collections. - */ -template <class T> class LIB_EXPORT CollectionManagerInterface : public CollectionManagerInterfaceBase { - friend class CollectionMediator<T>; - -public: - /** - * Extend a QAbstractItemModel to have the collection management interface. - * This will add the addBackend and a few other methods. - * - * This interface need to be used on a QAbstractItemModel derived class - * - * @param self "this" - */ - explicit CollectionManagerInterface(QAbstractItemModel* self); - virtual ~CollectionManagerInterface(); - - /** - * This method is used to add a collection to a model. The LoadOptions - * can be used to enforce some parameters. Please note this function is - * a variadic template. If the collection require some arguments to be passed - * to its constructor, they can be added as extra parameters. - * - * Please note that each collection need to take a CollectionMediator as first - * argument. - * - * @return The newly created collection - */ - template <class T2, typename ...Ts> - T2* addCollection(Ts... args, const LoadOptions options = LoadOptions::NONE); - - /** - * Set an object that will be used when the user wish to add a new collection - * of that type. - * - * That object can be a widget or anything. I will be passed when a creator - * is requested for that type of collection. - */ - template <class T2> - CollectionCreationInterface* registerCreator(CollectionCreationInterface* creator = nullptr); - - /** - * @see template <class T2> void registerCreator(CollectionCreationInterface* creator); - */ - template <class T2> - CollectionConfigurationInterface* registerConfigarator(CollectionConfigurationInterface* creator = nullptr); - - - /// Do this manager have active collections - bool hasEnabledCollections (FlagPack<CollectionInterface::SupportedFeatures> features = CollectionInterface::SupportedFeatures::NONE) const; - bool hasCollections (FlagPack<CollectionInterface::SupportedFeatures> features = CollectionInterface::SupportedFeatures::NONE) const; - - /// List all Collections - const QVector< CollectionInterface* > collections (FlagPack<CollectionInterface::SupportedFeatures> features = CollectionInterface::SupportedFeatures::NONE) const; - const QVector< CollectionInterface* > enabledCollections(FlagPack<CollectionInterface::SupportedFeatures> features = CollectionInterface::SupportedFeatures::NONE) const; - - ///Enable / disable a collection - bool enableCollection( CollectionInterface* collection, bool enabled); - - virtual bool clearAllCollections() const; - - /** - * Delete the item from the model and from its collection. This - * is permanent and cannot be undone. - * - * Please note that certain type of items, while removed from the view - * will continue to exist after being removed. This include items part - * of multiple Collections or items generated from runtime data. - * - * @return true if successful, false is the collection doesn't support removing items or the operation failed. - */ - bool deleteItem(T* item); - -private: - /** - * This method is called when a new collection is added. Some models - * may need to act on such action, other don't. - */ - virtual void collectionAddedCallback(CollectionInterface* collection); - - /** - * This method implement the logic necessary to add the item to - * the model. - * - * This method can be called with items already part of the model. - * All implementation must handle that. - * - * Please note that the constness is expected to be broken when using - * setData(), but not otherwise. - */ - virtual bool addItemCallback (const T* item) = 0; - - /** - * Remove an item from the model. Subclasses must implement the logic - * necessary to remove an item from the QAbstractCollection. - * - * This function can be called with nullptr or with items not part - * of the model. All implementations must handle that. - */ - virtual bool removeItemCallback(const T* item) = 0; - - CollectionManagerInterfacePrivate<T>* d_ptr; - QMutex m_InsertionMutex; -}; - -#include "collectionmanagerinterface.hpp" diff --git a/src/collectionmanagerinterface.hpp b/src/collectionmanagerinterface.hpp deleted file mode 100644 index 8eaa37033555803285c2abca9e1e4ea058917728..0000000000000000000000000000000000000000 --- a/src/collectionmanagerinterface.hpp +++ /dev/null @@ -1,225 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -template <class T> -class CollectionManagerInterfacePrivate -{ -public: - ///All manager should be QAbstractItemModel, this won't compile (on purpose) if the aren't - CollectionManagerInterfacePrivate(QAbstractItemModel* p2, CollectionManagerInterface<T>* p) : - m_pMediator(nullptr),q_ptr(p2),i_ptr(p) - {} - ~CollectionManagerInterfacePrivate(); - - QVector< CollectionInterface* > m_lCollections; - QVector< CollectionInterface* > m_lEnabledCollections; - mutable CollectionMediator<T>* m_pMediator; - QAbstractItemModel* q_ptr; - CollectionManagerInterface<T>* i_ptr; - - CollectionMediator<T>* itemMediator() const; - inline const QVector< CollectionInterface* > filterCollections(QVector< CollectionInterface* > in, FlagPack<CollectionInterface::SupportedFeatures> features) const; -}; - -template<class T> -CollectionMediator<T>* CollectionManagerInterfacePrivate<T>::itemMediator() const -{ - if (!m_pMediator) { - m_pMediator = new CollectionMediator<T>(i_ptr,q_ptr); - } - return m_pMediator; -} - -template<class T> -CollectionManagerInterfacePrivate<T>::~CollectionManagerInterfacePrivate() -{ - if (m_pMediator) - delete m_pMediator; -} - -template<class T> -template <class T2, typename ...Ts> -T2* CollectionManagerInterface<T>::addCollection(Ts... args, const LoadOptions options) -{ - T2* collection = new T2(d_ptr->itemMediator(),args...); - - //This will force the T2 to be a CollectionInterface subclass - CollectionInterface* b = collection; - d_ptr->m_lCollections << b; - - //This is the last time we have the class type (T2), so create a lambda - //to keep track of the configurator type while we still can - setCollectionConfigurator(collection,[this]() { - return registerConfigarator<T2>(); - }); - - if (options & LoadOptions::FORCE_ENABLED) { //TODO check is the collection is checked - - //Some collections can fail to load directly - //eventually it will necessary to add an async version of this - //to load the collection only when it is loaded - if (collection->load()) - d_ptr->m_lEnabledCollections << collection; - } - - registerToModel(collection); - - return collection; -} - -template<class T> -template <class T2> -CollectionCreationInterface* CollectionManagerInterface<T>::registerCreator(CollectionCreationInterface* creator) -{ - static CollectionCreationInterface* cfg = nullptr; - if (creator) { - cfg = creator; - addCreatorToList(creator); - } - return cfg; -} - -template<class T> -template <class T2> -CollectionConfigurationInterface* CollectionManagerInterface<T>::registerConfigarator(CollectionConfigurationInterface* configurator) -{ - static CollectionConfigurationInterface* cfg = nullptr; - if (configurator) { - cfg = configurator; - addConfiguratorToList(configurator); - } - return cfg; -} - -template<class T> -CollectionManagerInterface<T>::CollectionManagerInterface(QAbstractItemModel* self) : d_ptr(new CollectionManagerInterfacePrivate<T>(self,this)), -m_InsertionMutex(QMutex::Recursive) -{ - -} - -template<class T> -CollectionManagerInterface<T>::~CollectionManagerInterface() -{ - delete d_ptr; -} - -template<class T> -const QVector< CollectionInterface* > CollectionManagerInterfacePrivate<T>::filterCollections(QVector< CollectionInterface* > in, FlagPack<CollectionInterface::SupportedFeatures> features) const -{ - QVector< CollectionInterface* > out; - for (CollectionInterface* col : in) { - if ((col->supportedFeatures() & features) == features) - out << col; - } - return out; -} - -/** - * Return the list of all collections associated with this manager - * @param features An optional set of required features - * @note Please note that this method complexity is O(N) when "features" is set - */ -template<class T> -const QVector< CollectionInterface* > CollectionManagerInterface<T>::collections(FlagPack<CollectionInterface::SupportedFeatures> features) const -{ - if (features != CollectionInterface::SupportedFeatures::NONE) - return d_ptr->filterCollections(d_ptr->m_lCollections, features); - else - return d_ptr->m_lCollections; -} - -/** - * Return the list of all enabled collections associated with this manager - * @param features An optional set of required features - * @note Please note that this method complexity is O(N) when "features" is set - */ -template<class T> -const QVector< CollectionInterface* > CollectionManagerInterface<T>::enabledCollections(FlagPack<CollectionInterface::SupportedFeatures> features) const -{ - if (features != CollectionInterface::SupportedFeatures::NONE) - return d_ptr->filterCollections(d_ptr->m_lEnabledCollections, features); - else - return d_ptr->m_lEnabledCollections; -} - -/** - * Return if the manager has enabled collections - * @param features An optional set of required features - * @note Please note that this method complexity is O(N) when "features" is set - */ -template<class T> -bool CollectionManagerInterface<T>::hasEnabledCollections(FlagPack<CollectionInterface::SupportedFeatures> features) const -{ - if (features != CollectionInterface::SupportedFeatures::NONE) - return d_ptr->filterCollections(d_ptr->m_lEnabledCollections, features).size(); - else - return d_ptr->m_lEnabledCollections.size(); -} - -/** - * Return the list of all collections associated with this manager - * @param features An optional set of required features - * @note Please note that this method complexity is O(N) when "features" is set - */ -template<class T> -bool CollectionManagerInterface<T>::hasCollections(FlagPack<CollectionInterface::SupportedFeatures> features) const -{ - if (features != CollectionInterface::SupportedFeatures::NONE) - return d_ptr->filterCollections(d_ptr->m_lCollections, features).size(); - else - return d_ptr->m_lCollections.size(); -} - -template<class T> -bool CollectionManagerInterface<T>::clearAllCollections() const -{ - return false; -} - -template<class T> -void CollectionManagerInterface<T>::collectionAddedCallback(CollectionInterface* collection) -{ - Q_UNUSED(collection) -} - -template<class T> -bool CollectionManagerInterface<T>::deleteItem(T* item) -{ - if (item->collection()) { - if (item->collection()->model() != reinterpret_cast<QAbstractItemModel*>(this)) - qWarning() << "Item not deleted by its parent model"; - if (item->collection()->supportedFeatures() & CollectionInterface::SupportedFeatures::REMOVE) { - item->collection()->remove(item); - return true; - } - else - qDebug() << item << "cannot be deleted, the collection doesn't support removing items"; - } - else - qDebug() << item << "cannot be deleted, it has no collection"; - return false; -} - -template<class T> -bool CollectionManagerInterface<T>::enableCollection( CollectionInterface* collection, bool enabled) -{ - Q_UNUSED(enabled) //TODO implement it - collection->load(); - return true; -} diff --git a/src/collectionmediator.h b/src/collectionmediator.h deleted file mode 100644 index b1700d7bce5292bff83dd081f55fb2fb68a1dcb8..0000000000000000000000000000000000000000 --- a/src/collectionmediator.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -template<class T> -class CollectionManagerInterface; - -template<class T> -class CollectionMediatorPrivate; - -/** - * This is the base class for each BackendMediator. A backend mediator - * is a intermediary object between the backend and the model responsible - * to manage the collections objects. The purpose of this layer are: - * - * * Isolate the item gestion away from the manager public API - * * Work around the lack of polymorphic generics for template objects - * - * The later objective make it easier to later implement the decorator pattern. - */ -template<typename T> -class CollectionMediator { -public: - CollectionMediator(CollectionManagerInterface<T>* parentManager, QAbstractItemModel* m); - virtual ~CollectionMediator(); - bool addItem (const T* item); - bool removeItem(const T* item); - - QAbstractItemModel* model() const; - -private: - CollectionMediatorPrivate<T>* d_ptr; -}; - -#include <collectionmediator.hpp> diff --git a/src/collectionmediator.hpp b/src/collectionmediator.hpp deleted file mode 100644 index 13e8961353ad69ca1e54c5b194d9bf3c339b91ce..0000000000000000000000000000000000000000 --- a/src/collectionmediator.hpp +++ /dev/null @@ -1,61 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 <collectionmanagerinterface.h> - -template<class T> -class CollectionMediatorPrivate -{ -public: - CollectionManagerInterface<T>* m_pParent; - QAbstractItemModel* m_pModel; -}; - -template<typename T> -CollectionMediator<T>::CollectionMediator(CollectionManagerInterface<T>* parentManager, QAbstractItemModel* m) : - d_ptr(new CollectionMediatorPrivate<T>()) -{ - d_ptr->m_pParent = parentManager; - d_ptr->m_pModel = m; -} - -template<typename T> -CollectionMediator<T>::~CollectionMediator() -{ - delete d_ptr; -} - -template<typename T> -bool CollectionMediator<T>::addItem(const T* item) -{ - QMutexLocker l(&d_ptr->m_pParent->m_InsertionMutex); - return d_ptr->m_pParent->addItemCallback(item); -} - -template<typename T> -bool CollectionMediator<T>::removeItem(const T* item) -{ - QMutexLocker l(&d_ptr->m_pParent->m_InsertionMutex); - return d_ptr->m_pParent->removeItemCallback(item); -} - -template<typename T> -QAbstractItemModel* CollectionMediator<T>::model() const -{ - return d_ptr->m_pModel; -} diff --git a/src/collectionmodel.cpp b/src/collectionmodel.cpp deleted file mode 100644 index 67a8df29e36909f1e4985ffe0beaba5a5b95df22..0000000000000000000000000000000000000000 --- a/src/collectionmodel.cpp +++ /dev/null @@ -1,403 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "collectionmodel.h" - -//Qt -#include <QtCore/QCoreApplication> -#include <QtCore/QSortFilterProxyModel> - -//Ring -#include "collectionmanagerinterface.h" -#include "globalinstances.h" -#include "interfaces/itemmodelstateserializeri.h" -#include "collectionextensioninterface.h" -#include "private/collectionmodel_p.h" - -class ManageableCollectionProxy final : public QSortFilterProxyModel -{ -public: - ManageableCollectionProxy(QAbstractItemModel* parent) : QSortFilterProxyModel(parent) - { - setSourceModel(parent); - } - virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; -}; - -CollectionModelPrivate::CollectionModelPrivate(CollectionModel* parent) : QObject(parent),q_ptr(parent), -m_pManageableProxy(nullptr),m_NewCollectionMutex(QMutex::Recursive) -{} - - -CollectionModelPrivate::~CollectionModelPrivate() -{ -} - -CollectionModelPrivate::ProxyItem::~ProxyItem() -{ - foreach(ProxyItem* i, m_Children) - delete i; -} - -CollectionModel::CollectionModel(QObject* parent) : QAbstractTableModel(parent), d_ptr(new CollectionModelPrivate(this)) -{ - load(); -} - -CollectionModel::~CollectionModel() -{ - while (d_ptr->m_lTopLevelBackends.size()) { - CollectionModelPrivate::ProxyItem* item = d_ptr->m_lTopLevelBackends[0]; - d_ptr->m_lTopLevelBackends.remove(0); - while (item->m_Children.size()) { - //FIXME I don't think it can currently happen, but there may be - //more than 2 levels. - CollectionModelPrivate::ProxyItem* item2 = item->m_Children[0]; - item->m_Children.remove(0); - delete item2; - } - delete item; - } -} - -CollectionModel& CollectionModel::instance() -{ - static auto instance = new CollectionModel(QCoreApplication::instance()); - return *instance; -} - -QHash<int,QByteArray> CollectionModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles[static_cast<int>(Role::count ) ] = "count" ; - roles[static_cast<int>(Role::supportNone ) ] = "supportNone" ; - roles[static_cast<int>(Role::supportLoad ) ] = "supportLoad" ; - roles[static_cast<int>(Role::supportSave ) ] = "supportSave" ; - roles[static_cast<int>(Role::supportEdit ) ] = "supportEdit" ; - roles[static_cast<int>(Role::supportProbe ) ] = "supportProbe" ; - roles[static_cast<int>(Role::supportAdd ) ] = "supportAdd" ; - roles[static_cast<int>(Role::supportSave_all ) ] = "supportSave_all" ; - roles[static_cast<int>(Role::supportClear ) ] = "supportClear" ; - roles[static_cast<int>(Role::supportRemove ) ] = "supportRemove" ; - roles[static_cast<int>(Role::supportExport ) ] = "supportExport" ; - roles[static_cast<int>(Role::supportImport ) ] = "supportImport" ; - roles[static_cast<int>(Role::isEnableable ) ] = "isEnableable" ; - roles[static_cast<int>(Role::isDisableable ) ] = "isDisableable" ; - roles[static_cast<int>(Role::isManageable ) ] = "isManageable" ; - roles[static_cast<int>(Role::hasManageableChildren) ] = "hasManageableChildren" ; - - } - - return roles; -} - -QVariant CollectionModel::data (const QModelIndex& idx, int role) const -{ - if (idx.isValid()) { - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); - - /*if (idx.column() > 0 && item->collection) - return d_ptr->m_lExtensions[idx.column()-1]->data(item->collection,idx,role);*/ - - if (item->collection) { - switch(role) { - case Qt::DisplayRole: - return item->collection->name(); - case Qt::DecorationRole: - return item->collection->icon(); - case Qt::UserRole: // and Role::count - return 'x'+QString::number(item->collection->size()); - case Qt::CheckStateRole: { - try { - GlobalInstances::itemModelStateSerializer(); //TODO do better than that - return item->collection->isEnabled()?Qt::Checked:Qt::Unchecked; - } catch (...) { - break; - } - } - case static_cast<int>(Role::hasManageableChildren): - return item->manageableCount ? true : false; - }; - - //Retro-map to the SupportedFeatures //WARNING if SupportedFeatures change, this need to be updated - if (role > Qt::UserRole && role <= Qt::UserRole+14) { - return (bool) (role == Qt::UserRole+1 ? true : bool(item->collection->supportedFeatures() & ((CollectionInterface::SupportedFeatures)(0x01 << (role - Qt::UserRole - 2))))); - } - } - else { - switch(role) { - case Qt::DisplayRole: - return item->m_AltName; - case static_cast<int>(Role::hasManageableChildren): - return item->manageableCount ? true : false; - } - } - } - return QVariant(); -} - -int CollectionModel::rowCount (const QModelIndex& parent) const -{ - if (!parent.isValid()) { - return d_ptr->m_lTopLevelBackends.size(); - } - else { - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(parent.internalPointer()); - return item->m_Children.size(); - } -} - -int CollectionModel::columnCount (const QModelIndex& parent) const -{ - Q_UNUSED(parent) - return 1+d_ptr->m_lExtensions.size(); -} - -Qt::ItemFlags CollectionModel::flags(const QModelIndex& idx) const -{ - if (!idx.isValid()) - return 0; - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); - - //Categories can only be displayed - if (!item->collection) - return Qt::ItemIsEnabled; - - /*if (idx.column() > 0) { - //Make sure the cell is disabled if the row is - Qt::ItemFlags f = d_ptr->m_lExtensions[idx.column()-1]->flags(item->collection,idx); - return (((f&Qt::ItemIsEnabled)&&(!item->collection->isEnabled()))?f^Qt::ItemIsEnabled:f); - }*/ - const bool checkable = item->collection->supportedFeatures() & (CollectionInterface::SupportedFeatures::ENABLEABLE | - CollectionInterface::SupportedFeatures::DISABLEABLE | CollectionInterface::SupportedFeatures::MANAGEABLE ); - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | (checkable?Qt::ItemIsUserCheckable:Qt::NoItemFlags); -} - -bool CollectionModel::setData (const QModelIndex& idx, const QVariant &value, int role ) -{ - Q_UNUSED(idx) - Q_UNUSED(value) - Q_UNUSED(role) - /*if (idx.isValid() && idx.column() > 0) { - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); - return (!item->collection)?false : d_ptr->m_lExtensions[idx.column()-1]->setData(item->collection,idx,value,role); - }*/ - - if (role == Qt::CheckStateRole && idx.column() == 0) { - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); - if (item && item->collection) { - const bool old = item->collection->isEnabled(); - try { - GlobalInstances::itemModelStateSerializer().setChecked(item->collection,value==Qt::Checked); - emit dataChanged(index(idx.row(),0),index(idx.row(),columnCount()-1)); - - // The state change has been cached in the interface, but is not applied yet. - // it is necessary to keep track of the collection states that changed - if (d_ptr->m_hPendingChanges.contains(item->collection)) { - d_ptr->m_hPendingChanges.remove(item->collection); - emit checkStateChanged(); - } - else if (old != (value==Qt::Checked)) { - d_ptr->m_hPendingChanges[item->collection] = true; - emit checkStateChanged(); - } - return true; - } catch (...) { - qDebug() << "no ItemModelStateSerializer to set collection state"; - } - } - } - return false; -} - -QModelIndex CollectionModel::parent( const QModelIndex& idx ) const -{ - if (idx.isValid()) { - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(idx.internalPointer()); - if (!item->parent) - return QModelIndex(); - return createIndex(item->row,item->col,item->parent); - } - return QModelIndex(); -} - -QModelIndex CollectionModel::index( int row, int column, const QModelIndex& parent ) const -{ - if (parent.isValid() && parent.model() == this && row < rowCount(parent)) { - CollectionModelPrivate::ProxyItem* parentItem = static_cast<CollectionModelPrivate::ProxyItem*>(parent.internalPointer()); - CollectionModelPrivate::ProxyItem* item = nullptr; - if (row < parentItem->m_Children.size()) - item = parentItem->m_Children[row]; - else { - return QModelIndex(); - } - item->row = row; //FIXME dead code? - item->col = column; - return createIndex(row,column,item); - } - else { //Top level - CollectionModelPrivate::ProxyItem* item = nullptr; - if (row < d_ptr->m_lTopLevelBackends.size()) - item = d_ptr->m_lTopLevelBackends[row]; - else { - return QModelIndex(); - } - item->row = row; //FIXME dead code? - item->col = column; - return createIndex(item->row,item->col,item); - } -} - -void CollectionModelPrivate::slotUpdate() -{ - emit q_ptr->layoutChanged(); -} - -QVariant CollectionModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(section) - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) { - /*if (section > 0) - return d_ptr->m_lExtensions[section-1]->headerName();*/ - return QVariant(tr("Name")); - } - return QVariant(); -} - -bool CollectionModel::save() -{ - try { - - // Enable/disabled collections that changed - for (QHash<CollectionInterface*,bool>::const_iterator i = d_ptr->m_hPendingChanges.begin(); i != d_ptr->m_hPendingChanges.end(); ++i) { - i.key()->enable(GlobalInstances::itemModelStateSerializer().isChecked(i.key())); - } - - d_ptr->m_hPendingChanges.clear(); - - return GlobalInstances::itemModelStateSerializer().save(); - } catch (...) { - qDebug() << "no ItemModelStateSerializer exists"; - } - return false; -} - -bool CollectionModel::load() -{ - try { - return GlobalInstances::itemModelStateSerializer().load(); - } catch (...) { - return false; - } -} - -///Return the collection at a given index -CollectionInterface* CollectionModel::collectionAt(const QModelIndex& index) -{ - if (!index.isValid()) - return nullptr; - return static_cast<CollectionModelPrivate::ProxyItem*>(index.internalPointer())->collection; -} - -void CollectionModel::addExtension(CollectionExtensionInterface* extension) -{ - emit layoutAboutToBeChanged(); - d_ptr->m_lExtensions << extension; - connect(extension,SIGNAL(dataChanged(QModelIndex)),d_ptr.data(),SLOT(slotExtensionDataChanged(QModelIndex))); - emit layoutChanged(); -} - -void CollectionModelPrivate::slotExtensionDataChanged(const QModelIndex& idx) -{ - emit q_ptr->dataChanged(idx,idx); -} - -void CollectionModelPrivate::registerNew(CollectionInterface* col) -{ - if (!col) - return; - - QMutexLocker l(&m_NewCollectionMutex); - - ProxyItem* cat = m_hCategories[col->category()]; - if (col->category().isEmpty()){ - //TODO implement a default category - } - - if (!cat) { - cat = new ProxyItem(); - cat->parent = nullptr; - cat->row = m_lTopLevelBackends.size(); - cat->col = 0; - cat->m_AltName = col->category(); - cat->collection = nullptr; - - m_hCategories[cat->m_AltName] = cat; - m_hBackendsNodes[col] = cat; - - q_ptr->beginInsertRows(QModelIndex(),m_lTopLevelBackends.size(),m_lTopLevelBackends.size()); - m_lTopLevelBackends << cat; - q_ptr->endInsertRows(); - } - - ProxyItem* item = new ProxyItem(); - const bool hasParent = col->parent(); - ProxyItem* par = hasParent?m_hBackendsNodes[col->parent()] : cat; - - item->parent = par; - item->row = par->m_Children.size(); - item->col = 0; - q_ptr->beginInsertRows(q_ptr->createIndex(par->row,par->col,par),par->m_Children.size(),par->m_Children.size()); - par->m_Children << item; - q_ptr->endInsertRows(); - - //Make sure the manageable proxy get noticed things changed - if (col->supportedFeatures() & CollectionInterface::SupportedFeatures::MANAGEABLE) { - item->manageableCount++; - while(par) { - par->manageableCount++; - const QModelIndex& idx = q_ptr->createIndex(par->row,0,par); - emit q_ptr->dataChanged(idx,idx); - par = par->parent; - } - } - - item->collection = col ; - m_hBackendsNodes[col] = item; -} - -bool ManageableCollectionProxy::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const -{ - CollectionModelPrivate::ProxyItem* item = static_cast<CollectionModelPrivate::ProxyItem*>(sourceModel()->index(source_row,0,source_parent).internalPointer()); - return item ? item->manageableCount : false; -} - -/** - * Filter the CollectionModel to only keep the manageable collections. Those - * collections can be exposed and configured in the UI - */ -QAbstractItemModel* CollectionModel::manageableCollections() const -{ - if (!d_ptr->m_pManageableProxy) - d_ptr->m_pManageableProxy = new ManageableCollectionProxy(const_cast<CollectionModel*>(this)); - return d_ptr->m_pManageableProxy; -} - -#include <collectionmodel.moc> diff --git a/src/collectionmodel.h b/src/collectionmodel.h deleted file mode 100644 index 37c6f52ed4caa7939d855c8963ae98257b7a477d..0000000000000000000000000000000000000000 --- a/src/collectionmodel.h +++ /dev/null @@ -1,96 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" -#include "person.h" - -#include <QtCore/QAbstractItemModel> - -#include "collectionmanagerinterface.h" -#include "personmodel.h" -#include "collectioninterface.h" - -//Ring -class CollectionExtensionInterface; - -class CollectionModelPrivate; -class CollectionManagerInterfaceBase; - -class LIB_EXPORT CollectionModel : public QAbstractTableModel -{ - Q_OBJECT - - friend class CollectionManagerInterfaceBase; - - /** - * Imported from CollectionInterface::SupportedFeatures - */ - enum class Role { - count = Qt::UserRole, - supportNone , - supportLoad , - supportSave , - supportEdit , - supportProbe , - supportAdd , - supportSave_all , - supportClear , - supportRemove , - supportExport , - supportImport , - isEnableable , - isDisableable , - isManageable , - hasManageableChildren, - }; - -public: - explicit CollectionModel(QObject* parent = nullptr); - virtual ~CollectionModel(); - - virtual QVariant data (const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount (const QModelIndex& parent = QModelIndex() ) const override; - virtual int columnCount (const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags (const QModelIndex& index ) const override; - virtual QVariant headerData (int section, Qt::Orientation orientation, int role ) const override; - virtual bool setData (const QModelIndex& index, const QVariant &value, int role ) override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QHash<int,QByteArray> roleNames() const override; - - CollectionInterface* collectionAt(const QModelIndex& index); - - QAbstractItemModel* manageableCollections() const; - - void addExtension(CollectionExtensionInterface* extension); - - bool save(); - bool load(); - - static CollectionModel& instance(); - -Q_SIGNALS: - void checkStateChanged(); - -private: - QScopedPointer<CollectionModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(CollectionModel) - -}; - diff --git a/src/contactmethod.cpp b/src/contactmethod.cpp deleted file mode 100644 index fde283dd14d62dac95fb47d727fbcbda01ba2c52..0000000000000000000000000000000000000000 --- a/src/contactmethod.cpp +++ /dev/null @@ -1,910 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "contactmethod.h" - -//Qt -#include <QtCore/QCryptographicHash> -#include <QtCore/QDateTime> - -//Ring daemon -#include "dbus/configurationmanager.h" - -//Ring -#include "phonedirectorymodel.h" -#include "person.h" -#include "account.h" -#include "media/recordingmodel.h" -#include "private/person_p.h" -#include "private/contactmethod_p.h" -#include "call.h" -#include "dbus/presencemanager.h" -#include "numbercategorymodel.h" -#include "private/numbercategorymodel_p.h" -#include "numbercategory.h" -#include "certificate.h" -#include "accountmodel.h" -#include "certificatemodel.h" -#include "mime.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" - -//Private -#include "private/phonedirectorymodel_p.h" - -void ContactMethodPrivate::callAdded(Call* call) -{ - foreach (ContactMethod* n, m_lParents) - emit n->callAdded(call); -} - -void ContactMethodPrivate::changed() -{ - foreach (ContactMethod* n, m_lParents) - emit n->changed(); -} - -void ContactMethodPrivate::presentChanged(bool s) -{ - foreach (ContactMethod* n, m_lParents) - emit n->presentChanged(s); -} - -void ContactMethodPrivate::presenceMessageChanged(const QString& status) -{ - foreach (ContactMethod* n, m_lParents) - emit n->presenceMessageChanged(status); -} - -void ContactMethodPrivate::trackedChanged(bool t) -{ - foreach (ContactMethod* n, m_lParents) - emit n->trackedChanged(t); -} - -void ContactMethodPrivate::primaryNameChanged(const QString& name) -{ - foreach (ContactMethod* n, m_lParents) - emit n->primaryNameChanged(name); -} - -void ContactMethodPrivate::rebased(ContactMethod* other) -{ - foreach (ContactMethod* n, m_lParents) - emit n->rebased(other); -} - -void ContactMethodPrivate::registeredNameSet(const QString& name) -{ - foreach (ContactMethod* n, m_lParents) - emit n->registeredNameSet(name); -} - -ContactMethodPrivate::ContactMethodPrivate(const URI& uri, NumberCategory* cat, ContactMethod::Type st, ContactMethod* q) : - m_Uri(uri),m_pCategory(cat),m_Tracked(false),m_Present(false), - m_Type(st),m_PopularityIndex(-1),m_pPerson(nullptr),m_pAccount(nullptr), - m_IsBookmark(false), - m_Index(-1),m_hasType(false), m_pCertificate(nullptr), - m_Confirmed(false), q_ptr(q) -{} - -ContactMethod::ContactMethod() - : ContactMethod(QString(), NumberCategoryModel::other(), ContactMethod::Type::BLANK) -{} - -///Constructor -ContactMethod::ContactMethod(const URI& number, NumberCategory* cat, Type st) : ItemBase(&PhoneDirectoryModel::instance()), -d_ptr(new ContactMethodPrivate(number,cat,st,this)) -{ - setObjectName(d_ptr->m_Uri); - d_ptr->m_hasType = cat != NumberCategoryModel::other(); - if (d_ptr->m_hasType) { - NumberCategoryModel::instance().d_ptr->registerNumber(this); - } - d_ptr->m_lParents << this; -} - -ContactMethod::~ContactMethod() -{ - d_ptr->m_lParents.removeAll(this); - if (!d_ptr->m_lParents.size()) - delete d_ptr; -} - -///Return if this contact has confirmed the associated account -bool ContactMethod::isConfirmed() const -{ - return d_ptr->m_Confirmed; -} - -///Change the confirmed property -void ContactMethod::setConfirmed(bool confirmed) -{ - d_ptr->m_Confirmed = confirmed; - d_ptr->changed(); -} - -///Return if this number presence is being tracked -bool ContactMethod::isTracked() const -{ - //If the number doesn't support it, ignore the flag - return supportPresence() && d_ptr->m_Tracked; -} - -///Is this number present -bool ContactMethod::isPresent() const -{ - return d_ptr->m_Tracked && d_ptr->m_Present; -} - -///This number presence status string -QString ContactMethod::presenceMessage() const -{ - return d_ptr->m_PresentMessage; -} - -///Return the number -URI ContactMethod::uri() const { - return d_ptr->m_Uri ; -} - -///This phone number has a type -bool ContactMethod::hasType() const -{ - return d_ptr->m_hasType; -} - -///Protected getter to get the number index -int ContactMethod::index() const -{ - return d_ptr->m_Index; -} - -///Return the phone number type -NumberCategory* ContactMethod::category() const { - return d_ptr->m_pCategory ; -} - -///Return this number associated account, if any -Account* ContactMethod::account() const -{ - return d_ptr->m_pAccount; -} - -///Return this number associated contact, if any -Person* ContactMethod::contact() const -{ - return d_ptr->m_pPerson; -} - -///Return when this number was last used -time_t ContactMethod::lastUsed() const -{ - return d_ptr->m_UsageStats.lastUsed(); -} - -///Set this number default account -void ContactMethod::setAccount(Account* account) -{ - //Add the statistics - if (account && !d_ptr->m_pAccount) - account->usageStats += d_ptr->m_UsageStats; - - d_ptr->m_pAccount = account; - - //The sha1 is no longer valid - d_ptr->m_Sha1.clear(); - - if (d_ptr->m_pAccount) - connect (d_ptr->m_pAccount,SIGNAL(destroyed(QObject*)),this,SLOT(accountDestroyed(QObject*))); - - //Track Ring contacts by default - if (this->protocolHint() == URI::ProtocolHint::RING || this->protocolHint() == URI::ProtocolHint::RING_USERNAME) { - setTracked(true); - } - - d_ptr->changed(); -} - -///Set this number contact -void ContactMethod::setPerson(Person* contact) -{ - Person* old = d_ptr->m_pPerson; - if (d_ptr->m_pPerson == contact) - return; - - d_ptr->m_pPerson = contact; - - //The sha1 is no longer valid - d_ptr->m_Sha1.clear(); - - if (contact) - contact->d_ptr->registerContactMethod(this); - - if (contact && d_ptr->m_Type != ContactMethod::Type::TEMPORARY) { - contact->d_ptr->registerContactMethod(this); - PhoneDirectoryModel::instance().d_ptr->indexNumber(this,d_ptr->m_hNames.keys()+QStringList(contact->formattedName())); - d_ptr->m_PrimaryName_cache = contact->formattedName(); - d_ptr->primaryNameChanged(d_ptr->m_PrimaryName_cache); - connect(contact,SIGNAL(rebased(Person*)),this,SLOT(contactRebased(Person*))); - } - d_ptr->changed(); - - emit contactChanged(contact, old); -} - -///Protected setter to set if there is a type -void ContactMethod::setHasType(bool value) -{ - d_ptr->m_hasType = value; -} - -///Protected setter to set the PhoneDirectoryModel index -void ContactMethod::setIndex(int value) -{ - d_ptr->m_Index = value; -} - -///Protected setter to change the popularity index -void ContactMethod::setPopularityIndex(int value) -{ - d_ptr->m_PopularityIndex = value; -} - -void ContactMethod::setCategory(NumberCategory* cat) -{ - if (cat == d_ptr->m_pCategory) return; - if (d_ptr->m_hasType) - NumberCategoryModel::instance().d_ptr->unregisterNumber(this); - d_ptr->m_hasType = cat != NumberCategoryModel::other(); - d_ptr->m_pCategory = cat; - if (d_ptr->m_hasType) - NumberCategoryModel::instance().d_ptr->registerNumber(this); - d_ptr->changed(); -} - -void ContactMethod::setBookmarked(bool bookmarked ) -{ - d_ptr->m_IsBookmark = bookmarked; -} - -///Force an Uid on this number (instead of hash) -void ContactMethod::setUid(const QString& uri) -{ - d_ptr->m_Uid = uri; -} - -///Attempt to change the number type -bool ContactMethod::setType(ContactMethod::Type t) -{ - if (d_ptr->m_Type == ContactMethod::Type::BLANK) - return false; - if (account() && t == ContactMethod::Type::ACCOUNT) { - if (account()->supportPresenceSubscribe()) { - d_ptr->m_Tracked = true; //The daemon will init the tracker itself - d_ptr->trackedChanged(true); - } - d_ptr->m_Type = t; - return true; - } - return false; -} - -///Update the last time used only if t is more recent than m_LastUsed -void ContactMethod::setLastUsed(time_t t) -{ - if (d_ptr->m_UsageStats.setLastUsed(t)) - emit lastUsedChanged(t); -} - -///Set if this number is tracking presence information -void ContactMethod::setTracked(bool track) -{ - if (track != d_ptr->m_Tracked) { //Subscribe only once - //You can't subscribe without account - if (track && !d_ptr->m_pAccount) return; - d_ptr->m_Tracked = track; - PresenceManager::instance().subscribeBuddy(d_ptr->m_pAccount->id(), - uri().format(URI::Section::CHEVRONS | - URI::Section::SCHEME | - URI::Section::USER_INFO | - URI::Section::HOSTNAME), - track); - d_ptr->changed(); - d_ptr->trackedChanged(track); - } -} - -/// Set the registered name -void ContactMethodPrivate::setRegisteredName(const QString& registeredName) -{ - if (registeredName.isEmpty() || registeredName == m_RegisteredName) - return; - - // If this happens, better create another ContactMethod manually to avoid - // all the corner cases. Doing this, for example, allows to keep track of - // the name in the private index of unique names kept by the - // PhoneDirectoryModel - if (!m_RegisteredName.isEmpty()) { - qWarning() << "A registered name is already set for this ContactMethod" - << m_RegisteredName << registeredName; - return; - } - - m_RegisteredName = registeredName; - registeredNameSet(registeredName); - changed(); -} - -///Allow phonedirectorymodel to change presence status -void ContactMethod::setPresent(bool present) -{ - if (d_ptr->m_Present != present) { - d_ptr->m_Present = present; - d_ptr->presentChanged(present); - } -} - -void ContactMethod::setPresenceMessage(const QString& message) -{ - if (d_ptr->m_PresentMessage != message) { - d_ptr->m_PresentMessage = message; - d_ptr->presenceMessageChanged(message); - } -} - -///Return the current type of the number -ContactMethod::Type ContactMethod::type() const -{ - return d_ptr->m_Type; -} - -///Return the number of calls from this number -int ContactMethod::callCount() const -{ - return d_ptr->m_UsageStats.totalCount(); -} - -uint ContactMethod::weekCount() const -{ - return d_ptr->m_UsageStats.lastWeekCount(); -} - -uint ContactMethod::trimCount() const -{ - return d_ptr->m_UsageStats.lastTrimCount(); -} - -bool ContactMethod::haveCalled() const -{ - return d_ptr->m_UsageStats.haveCalled(); -} - -///Best bet for this person real name -QString ContactMethod::primaryName() const -{ - //Compute the primary name - if (d_ptr->m_PrimaryName_cache.isEmpty()) { - QString ret; - if (d_ptr->m_hNames.size() == 1) - ret = d_ptr->m_hNames.constBegin().key(); - else { - QString toReturn = uri(); - QPair<int, time_t> max = {0, 0}; - - for (QHash<QString,QPair<int, time_t>>::const_iterator i = d_ptr->m_hNames.begin(); i != d_ptr->m_hNames.end(); ++i) { - if (this->protocolHint() == URI::ProtocolHint::RING && - i.value().second > max.second) { - max.second = i.value().second; - toReturn = i.key (); - } - else if (i.value().first > max.first) { - max.first = i.value().first; - toReturn = i.key (); - } - } - ret = toReturn; - } - const_cast<ContactMethod*>(this)->d_ptr->m_PrimaryName_cache = ret; - const_cast<ContactMethod*>(this)->d_ptr->primaryNameChanged(d_ptr->m_PrimaryName_cache); - } - //Fallback: Use the URI - if (d_ptr->m_PrimaryName_cache.isEmpty()) { - return uri(); - } - - //Return the cached primaryname - return d_ptr->m_PrimaryName_cache; -} - -/// Returns the best possible name for the contact method in order of priority: -/// 1. Formatted name of associated Person -/// 2. Registered name (for RING type) -/// 3. "primary name" (could be a SIP display name received during a call or uri as fallback) -QString ContactMethod::bestName() const -{ - QString name; - if (contact() and !contact()->formattedName().isEmpty()) - name = contact()->formattedName(); - else if (not registeredName().isEmpty()) - name = registeredName(); - else - name = primaryName(); - - return name; -} - -/// Returns the registered username otherwise returns an empty QString -QString ContactMethod::registeredName() const -{ - return d_ptr->m_RegisteredName.isEmpty()? QString() : d_ptr->m_RegisteredName; -} - -/// Returns the registered name if available, otherwise returns the uri -/// Deprecated for not following LRC naming convention, please use bestId() instead -QString ContactMethod::getBestId() const -{ - return bestId(); -} - -/// Returns the registered name if available, otherwise returns the uri -QString ContactMethod::bestId() const -{ - return registeredName().isEmpty() ? uri() : registeredName(); -} - -/** - * Return if this ContactMethod pointer is the `master` one or a deduplicated - * proxy. - * - * Contact methods can be merged over time to avoid both the memory overhead - * and diverging statistics / presence / messaging. As explained in `merge()`, - * the old pointers are kept alive as they are proxies to the real object - * (d_ptr). This accessor helps some algorithm detect if they can safely get - * rid of this CM as a "better" one already exists (assuming the track all CMs). - */ -bool ContactMethod::isDuplicate() const -{ - return d_ptr->m_lParents.first() != this; -} - -///Is this number bookmarked -bool ContactMethod::isBookmarked() const -{ - return d_ptr->m_IsBookmark; -} - -///If this number could (theoretically) support presence status -bool ContactMethod::supportPresence() const -{ - //Without an account, presence is impossible - if (!d_ptr->m_pAccount) - return false; - //The account also have to support it - if (!d_ptr->m_pAccount->supportPresenceSubscribe()) - return false; - - //In the end, it all come down to this, is the number tracked - return true; -} - -///Proxy accessor to the category icon -QVariant ContactMethod::icon() const -{ - return category()->icon(isTracked(),isPresent()); -} - -///The number of seconds spent with the URI (from history) -int ContactMethod::totalSpentTime() const -{ - return d_ptr->m_UsageStats.totalSeconds(); -} - -///Return this number unique identifier (hash) -QString ContactMethod::uid() const -{ - return d_ptr->m_Uid.isEmpty()?toHash():d_ptr->m_Uid; -} - -///Return the URI protocol hint -URI::ProtocolHint ContactMethod::protocolHint() const -{ - return d_ptr->m_Uri.protocolHint(); -} - -///Create a SHA1 hash identifying this contact method -QByteArray ContactMethod::sha1() const -{ - if (d_ptr->m_Sha1.isEmpty()) { - QCryptographicHash hash(QCryptographicHash::Sha1); - hash.addData(toHash().toLatin1()); - - //Create a reproducible key for this file - d_ptr->m_Sha1 = hash.result().toHex(); - } - return d_ptr->m_Sha1; -} - -///Return all calls from this number -QList<Call*> ContactMethod::calls() const -{ - return d_ptr->m_lCalls; -} - -///Return the phonenumber position in the popularity index -int ContactMethod::popularityIndex() const -{ - return d_ptr->m_PopularityIndex; -} - -QHash<QString,QPair<int, time_t>> ContactMethod::alternativeNames() const -{ - return d_ptr->m_hNames; -} - -QVariant ContactMethod::roleData(int role) const -{ - QVariant cat; - - auto lastCall = d_ptr->m_lCalls.isEmpty() ? nullptr : d_ptr->m_lCalls.last(); - - switch (role) { - case static_cast<int>(Ring::Role::Name): - case static_cast<int>(Call::Role::Name): - cat = bestName(); - break; - case Qt::ToolTipRole: - cat = presenceMessage(); - break; - case static_cast<int>(Ring::Role::URI): - case static_cast<int>(Role::Uri): - cat = uri(); - break; - case Qt::DisplayRole: - case Qt::EditRole: - case static_cast<int>(Ring::Role::Number): - case static_cast<int>(Call::Role::Number): - cat = bestId(); - break; - case Qt::DecorationRole: - return GlobalInstances::pixmapManipulator().decorationRole(this); - case static_cast<int>(Call::Role::Direction): - cat = cat = !lastCall ? QVariant() : QVariant::fromValue(lastCall->direction()); - break; - case static_cast<int>(Ring::Role::LastUsed): - case static_cast<int>(Call::Role::Date): - cat = d_ptr->m_UsageStats.lastUsed() <= 0 ? QVariant() : QDateTime::fromTime_t(d_ptr->m_UsageStats.lastUsed()); - break; - case static_cast<int>(Ring::Role::Length): - case static_cast<int>(Call::Role::Length): - cat = cat = !lastCall ? QVariant() : lastCall->length(); - break; - case static_cast<int>(Ring::Role::FormattedLastUsed): - case static_cast<int>(Call::Role::FormattedDate): - case static_cast<int>(Call::Role::FuzzyDate): - cat = QVariant(); - break; - case static_cast<int>(Ring::Role::IndexedLastUsed): - return QVariant(); - case static_cast<int>(Call::Role::HasAVRecording): - cat = cat = !lastCall ? QVariant() : lastCall->isAVRecording(); - break; - case static_cast<int>(Call::Role::ContactMethod): - case static_cast<int>(Ring::Role::Object): - case static_cast<int>(Role::Object): - cat = QVariant::fromValue(const_cast<ContactMethod*>(this)); - break; - case static_cast<int>(Ring::Role::ObjectType): - cat = QVariant::fromValue(Ring::ObjectType::ContactMethod); - break; - case static_cast<int>(Call::Role::IsBookmark): - cat = false; - break; - case static_cast<int>(Call::Role::Filter): - cat = uri()+primaryName(); - break; - case static_cast<int>(Ring::Role::IsPresent): - case static_cast<int>(Call::Role::IsPresent): - cat = isPresent(); - break; - case static_cast<int>(Call::Role::Photo): - if (contact()) - cat = contact()->photo(); - break; - case static_cast<int>(Role::CategoryIcon): - if (category()) - cat = d_ptr->m_pCategory->icon(isTracked(), isPresent()); - break; - case static_cast<int>(Call::Role::LifeCycleState): - return QVariant::fromValue(Call::LifeCycleState::FINISHED); - } - return cat; -} - -QMimeData* ContactMethod::mimePayload() const -{ - return RingMimes::payload(nullptr, this, nullptr); -} - -///Add a call to the call list, notify listener -void ContactMethod::addCall(Call* call) -{ - if (!call) return; - - d_ptr->m_Type = ContactMethod::Type::USED; - d_ptr->m_lCalls << call; - - // call setLastUsed first so that we emit lastUsedChanged() - auto time = call->startTimeStamp(); - setLastUsed(time); - - //Update the contact method statistics - d_ptr->m_UsageStats.update(call->startTimeStamp(), call->stopTimeStamp()); - if (d_ptr->m_pAccount) - d_ptr->m_pAccount->usageStats.update(call->startTimeStamp(), call->stopTimeStamp()); - - if (call->direction() == Call::Direction::OUTGOING) { - d_ptr->m_UsageStats.setHaveCalled(); - if (d_ptr->m_pAccount) - d_ptr->m_pAccount->usageStats.setHaveCalled(); - } - - if (d_ptr->m_pAccount) - d_ptr->m_pAccount->usageStats.setLastUsed(time); - - d_ptr->callAdded(call); - d_ptr->changed(); -} - -///Generate an unique representation of this number -QString ContactMethod::toHash() const -{ - QString uristr; - - switch(uri().protocolHint()) { - case URI::ProtocolHint::RING : - //There is no point in keeping the full URI, a Ring hash is unique - uristr = uri().userinfo(); - break; - case URI::ProtocolHint::UNRECOGNIZED: - case URI::ProtocolHint::RING_USERNAME: - case URI::ProtocolHint::SIP_OTHER: - case URI::ProtocolHint::IP : - case URI::ProtocolHint::SIP_HOST : - //Some URI have port number in them. They have to be stripped prior to the hash creation - uristr = uri().format( - URI::Section::CHEVRONS | - URI::Section::SCHEME | - URI::Section::USER_INFO | - URI::Section::HOSTNAME - ); - break; - } - - return QString("%1///%2///%3") - .arg( - uristr - ) - .arg( - account()?account()->id():QString() - ) - .arg( - contact()?contact()->uid():QString() - ); -} - -///Increment name counter and update indexes -void ContactMethod::incrementAlternativeName(const QString& name, const time_t lastUsed) -{ - const bool needReIndexing = !d_ptr->m_hNames[name].first; - if (d_ptr->m_hNames[name].second < lastUsed) - d_ptr->m_hNames[name].second = lastUsed; - d_ptr->m_hNames[name].first++; - if (needReIndexing && d_ptr->m_Type != ContactMethod::Type::TEMPORARY) { - PhoneDirectoryModel::instance().d_ptr->indexNumber(this,d_ptr->m_hNames.keys()+(d_ptr->m_pPerson?(QStringList(d_ptr->m_pPerson->formattedName())):QStringList())); - //Invalid m_PrimaryName_cache - if (!d_ptr->m_pPerson) - d_ptr->m_PrimaryName_cache.clear(); - } - - emit changed(); -} - -void ContactMethod::accountDestroyed(QObject* o) -{ - if (o == d_ptr->m_pAccount) - d_ptr->m_pAccount = nullptr; -} - -/** - * When the ContactMethod contact is merged with another one, the phone number - * data might be replaced, like the preferred name. - */ -void ContactMethod::contactRebased(Person* other) -{ - d_ptr->m_PrimaryName_cache = other->formattedName(); - d_ptr->primaryNameChanged(d_ptr->m_PrimaryName_cache); - setPerson(other); - - d_ptr->changed(); - d_ptr->rebased(this); -} - -/** - * Merge two phone number to share the same data. This avoid having to change - * pointers all over the place. The ContactMethod objects remain intact, the - * PhoneDirectoryModel will replace the old references, but existing ones will - * keep working. - */ -bool ContactMethod::merge(ContactMethod* other) -{ - - if ((!other) || other == this || other->d_ptr == d_ptr) - return false; - - //This is invalid, those are different numbers - if (account() && other->account() && account() != other->account()) - return false; - - //TODO Check if the merge is valid - - //TODO Merge the alternative names - - if (d_ptr->m_Tracked) - other->d_ptr->m_Tracked = true; - - if (d_ptr->m_Present) - other->d_ptr->m_Present = true; - - if (contact() && !other->contact()) - other->setPerson(contact()); - - if ((!registeredName().isEmpty()) && other->registeredName().isEmpty()) - other->d_ptr->setRegisteredName(registeredName()); - - const QString oldName = primaryName(); - - ContactMethodPrivate* currentD = d_ptr; - - //Replace the D-Pointer - this->d_ptr= other->d_ptr; - d_ptr->m_lParents << this; - - //In case the URI is different, take the longest and most precise - //TODO keep a log of all URI used - if (currentD->m_Uri.size() > other->d_ptr->m_Uri.size()) { - other->d_ptr->m_lOtherURIs << other->d_ptr->m_Uri; - other->d_ptr->m_Uri = currentD->m_Uri; - } - else - other->d_ptr->m_lOtherURIs << currentD->m_Uri; - - emit changed(); - emit rebased(other); - - if (oldName != primaryName()) - d_ptr->primaryNameChanged(primaryName()); - - currentD->m_lParents.removeAll(this); - if (!currentD->m_lParents.size()) - delete currentD; - return true; -} - -bool ContactMethod::operator==(ContactMethod* other) -{ - return other && this->d_ptr== other->d_ptr; -} - -bool ContactMethod::operator==(const ContactMethod* other) const -{ - return other && this->d_ptr== other->d_ptr; -} - -bool ContactMethod::operator==(ContactMethod& other) -{ - return this->d_ptr== other.d_ptr; -} - -bool ContactMethod::operator==(const ContactMethod& other) const -{ - return this->d_ptr== other.d_ptr; -} - -bool ContactMethod::isReachable() const -{ - auto& m = AccountModel::instance(); - - const bool hasSip = m.isSipSupported (); - const bool hasIP2IP = m.isIP2IPSupported(); - const bool hasRing = m.isRingSupported (); - - switch (protocolHint()) { - case URI::ProtocolHint::SIP_HOST : - case URI::ProtocolHint::IP : - if (hasIP2IP) - return true; - //no break - [[clang::fallthrough]]; - case URI::ProtocolHint::SIP_OTHER: - if (hasSip) - return true; - break; - case URI::ProtocolHint::RING: - case URI::ProtocolHint::RING_USERNAME: - if (hasRing) - return true; - break; - case URI::ProtocolHint::UNRECOGNIZED: - if (hasRing || hasSip) - return true; - break; - } - - return false; -} - -Certificate* ContactMethod::certificate() const -{ - if (!d_ptr->m_pCertificate && protocolHint() == URI::ProtocolHint::RING) - d_ptr->m_pCertificate = CertificateModel::instance().getCertificateFromId(uri().userinfo(), account()); - - if (d_ptr->m_pCertificate && !d_ptr->m_pCertificate->contactMethod()) - d_ptr->m_pCertificate->setContactMethod(const_cast<ContactMethod*>(this)); - - return d_ptr->m_pCertificate; -} - -void ContactMethodPrivate::setCertificate(Certificate* certificate) -{ - m_pCertificate = certificate; - if (!certificate->contactMethod()) - certificate->setContactMethod(q_ptr); -} - - -/************************************************************************************ - * * - * Temporary phone number * - * * - ***********************************************************************************/ - -///Constructor -TemporaryContactMethod::TemporaryContactMethod(const ContactMethod* number) : - ContactMethod(QString(),NumberCategoryModel::other(),ContactMethod::Type::TEMPORARY),d_ptr(nullptr) -{ - if (number) { - setPerson(number->contact()); - setAccount(number->account()); - } -} - -void TemporaryContactMethod::setUri(const URI& uri) -{ - ContactMethod::d_ptr->m_Uri = uri; - - //The sha1 is no longer valid - ContactMethod::d_ptr->m_Sha1.clear(); - ContactMethod::d_ptr->changed(); -} - -QVariant TemporaryContactMethod::icon() const -{ - return QVariant(); //TODO use the pixmapmanipulator to get a better icon -} - -Q_DECLARE_METATYPE(QList<Call*>) diff --git a/src/contactmethod.h b/src/contactmethod.h deleted file mode 100644 index d20bc073c3f6e7345b9278aa5dbc350a7526f867..0000000000000000000000000000000000000000 --- a/src/contactmethod.h +++ /dev/null @@ -1,248 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" -#include <time.h> -#include <itembase.h> - -//Qt -#include <QStringList> -#include <QtCore/QSize> -#include <QtCore/QObject> -#include <QtCore/QSharedPointer> - -//Ring -#include "itemdataroles.h" -#include "uri.h" -class Account; -class AccountPrivate; -class Person; -class Call; -class ContactMethodPrivate; -class TemporaryContactMethod; -class NumberCategory; -class TemporaryContactMethodPrivate; -class InstantMessagingModel; -class Certificate; - -///ContactMethod: represent a phone number -class LIB_EXPORT ContactMethod : public ItemBase -{ - Q_OBJECT -public: - friend class PhoneDirectoryModel; - friend class PhoneDirectoryModelPrivate; - friend class CallPrivate; - friend class AccountPrivate; - - enum class Role { - Uri = static_cast<int>(Ring::Role::UserRole) + 1000, - Object , - CategoryIcon , - //TODO implement all others - }; - - //Properties - Q_PROPERTY(Account* account READ account WRITE setAccount ) - Q_PROPERTY(Person* person READ contact WRITE setPerson ) - Q_PROPERTY(int lastUsed READ lastUsed WRITE setLastUsed ) - Q_PROPERTY(QString uri READ uri ) - Q_PROPERTY(int callCount READ callCount ) - Q_PROPERTY(QList<Call*> calls READ calls ) - Q_PROPERTY(int popularityIndex READ popularityIndex ) - Q_PROPERTY(bool bookmarked READ isBookmarked ) - Q_PROPERTY(QString uid READ uid WRITE setUid ) - Q_PROPERTY(bool isTracked READ isTracked NOTIFY trackedChanged ) - Q_PROPERTY(bool isPresent READ isPresent NOTIFY presentChanged ) - Q_PROPERTY(bool supportPresence READ supportPresence ) - Q_PROPERTY(QString presenceMessage READ presenceMessage NOTIFY presenceMessageChanged ) - Q_PROPERTY(uint weekCount READ weekCount ) - Q_PROPERTY(uint trimCount READ trimCount ) - Q_PROPERTY(bool haveCalled READ haveCalled ) - Q_PROPERTY(QString primaryName READ primaryName ) - Q_PROPERTY(bool isBookmarked READ isBookmarked ) - Q_PROPERTY(QVariant icon READ icon ) - Q_PROPERTY(int totalSpentTime READ totalSpentTime ) - Q_PROPERTY(URI::ProtocolHint protocolHint READ protocolHint ) - Q_PROPERTY(bool isReachable READ isReachable ) - Q_PROPERTY(Certificate* certificate READ certificate ) - Q_PROPERTY(QString registeredName READ registeredName NOTIFY registeredNameSet ) - Q_PROPERTY(QString bestId READ bestId ) - Q_PROPERTY(QString bestName READ bestName ) - Q_PROPERTY(bool isConfirmed READ isConfirmed WRITE setConfirmed ) - -// Q_PROPERTY(QHash<QString,int> alternativeNames READ alternativeNames ) - - ///@enum Type: Is this temporary, blank, used or unused - enum class Type { - BLANK = 0, /*!< This number represent no number */ - TEMPORARY = 1, /*!< This number is not yet complete */ - USED = 2, /*!< This number have been called before */ - UNUSED = 3, /*!< This number have never been called, but is in the address book */ - ACCOUNT = 4, /*!< This number correspond to the URI of a SIP account */ - }; - Q_ENUMS(Type) - - //Constructor - ContactMethod(); /*! construct an instance set with Type::BLANK */ - - //Getters - URI uri () const; - NumberCategory* category () const; - bool isTracked () const; - bool isPresent () const; - QString presenceMessage () const; - Account* account () const; - Person* contact () const; - time_t lastUsed () const; - ContactMethod::Type type () const; - int callCount () const; - uint weekCount () const; - uint trimCount () const; - bool haveCalled () const; - QList<Call*> calls () const; - int popularityIndex () const; - QHash<QString, QPair<int, time_t>> alternativeNames() const; - QString primaryName () const; - bool isBookmarked () const; - bool supportPresence () const; - virtual QVariant icon () const; - int totalSpentTime () const; - QString uid () const; - URI::ProtocolHint protocolHint () const; - QByteArray sha1 () const; - bool isReachable () const; - Certificate* certificate () const; - QString registeredName () const; - Q_DECL_DEPRECATED QString getBestId () const; - QString bestId () const; - bool isDuplicate () const; - QString bestName () const; - bool isConfirmed () const; - - /* - * Returns roles associated on ContactMethod based on Call::Roles - * Returns last call info when querying info on call associated to this contact method - */ - Q_INVOKABLE QVariant roleData (int role) const; - Q_INVOKABLE QMimeData* mimePayload( ) const; - - //Setters - Q_INVOKABLE void setAccount (Account* account ); - Q_INVOKABLE void setPerson (Person* contact ); - Q_INVOKABLE void setTracked (bool track ); - void setCategory (NumberCategory* cat ); - void setBookmarked (bool bookmarked ); - void setUid (const QString& uri ); - bool setType (ContactMethod::Type t ); - void setLastUsed (time_t t ); - void setPresent (bool present ); - void setConfirmed (bool confirmed ); - - //Mutator - Q_INVOKABLE void addCall(Call* call); - Q_INVOKABLE void incrementAlternativeName(const QString& name, const time_t lastUsed); - - //Helper - QString toHash() const; - - //Operator - bool operator==(ContactMethod* other); - bool operator==(const ContactMethod* other) const; - bool operator==(ContactMethod& other); - bool operator==(const ContactMethod& other) const; - -protected: - //Constructor - ContactMethod(const URI& uri, NumberCategory* cat, Type st = Type::UNUSED); - virtual ~ContactMethod(); - - //Private setters - void setPresenceMessage(const QString& message); - - //PhoneDirectoryModel mutator - bool merge(ContactMethod* other); - - //Getter - bool hasType() const; - int index() const; - - //Setter - void setHasType(bool value); - void setIndex(int value); - void setPopularityIndex(int value); - - //Many phone numbers can have the same "d" if they were merged - ContactMethodPrivate* d_ptr; - -private: - friend class ContactMethodPrivate; - -private Q_SLOTS: - void accountDestroyed(QObject* o); - void contactRebased(Person* other); - -Q_SIGNALS: - ///A new call have used this ContactMethod - void callAdded ( Call* call ); - ///A property associated with this number has changed - void changed ( ); - ///The presence status of this phone number has changed - void presentChanged ( bool ); - ///The presence status message associated with this number - void presenceMessageChanged( const QString& ); - ///This number track presence - void trackedChanged ( bool ); - /** - * The name used to be represent this number has changed - * It is important for user of this object to track this - * as the name will change over time as new contact - * sources are added - */ - void primaryNameChanged ( const QString& name ); - /** - * Two previously independent number have been merged - * this happen when new information cues prove that number - * with previously ambiguous data - */ - void rebased ( ContactMethod* other ); - ///The most recent time there was an interaction with this CM changed - void lastUsedChanged(time_t t); - ///The person attached to this CM has changed - void contactChanged(Person* newContact, Person* oldContact); - /// The number of unread text messages has changed - void unreadTextMessageCountChanged(); - /// When the registered name is set - void registeredNameSet(const QString& name); -}; - -Q_DECLARE_METATYPE(ContactMethod*) - -///@class TemporaryContactMethod: An incomplete phone number -class LIB_EXPORT TemporaryContactMethod : public ContactMethod { - Q_OBJECT -public: - explicit TemporaryContactMethod(const ContactMethod* number = nullptr); - virtual QVariant icon() const override; - void setUri(const URI& uri); - -private: - TemporaryContactMethodPrivate* d_ptr; - Q_DECLARE_PRIVATE(TemporaryContactMethod) -}; diff --git a/src/contactmodel.cpp b/src/contactmodel.cpp index 04b262ad361af0d566a8e05ce18228e7992a79b8..a4ea9c999fdedc68386a0bf72cd79a8fd8a130a5 100644 --- a/src/contactmodel.cpp +++ b/src/contactmodel.cpp @@ -38,7 +38,7 @@ #include "api/newaccountmodel.h" #include "callbackshandler.h" #include "uri.h" -#include "private/vcardutils.h" +#include "vcard.h" #include "authority/daemon.h" #include "authority/databasehelper.h" @@ -531,7 +531,7 @@ ContactModelPimpl::fillsWithRINGContacts() { auto contactUri = tr_info[DRing::Account::TrustRequest::FROM]; - const auto vCard = VCardUtils::toHashMap(payload); + const auto vCard = lrc::vCard::utils::toHashMap(payload); const auto alias = vCard["FN"]; const auto photo = (vCard.find("PHOTO;ENCODING=BASE64;TYPE=PNG") == vCard.end()) ? vCard["PHOTO;ENCODING=BASE64;TYPE=JPEG"] : vCard["PHOTO;ENCODING=BASE64;TYPE=PNG"]; @@ -778,7 +778,7 @@ ContactModelPimpl::slotIncomingContactRequest(const std::string& accountId, { std::lock_guard<std::mutex> lk(contactsMtx_); if (contacts.find(contactUri) == contacts.end()) { - const auto vCard = VCardUtils::toHashMap(payload.c_str()); + const auto vCard = lrc::vCard::utils::toHashMap(payload.c_str()); const auto alias = vCard["FN"]; const auto photo = (vCard.find("PHOTO;ENCODING=BASE64;TYPE=PNG") == vCard.end()) ? vCard["PHOTO;ENCODING=BASE64;TYPE=JPEG"] : vCard["PHOTO;ENCODING=BASE64;TYPE=PNG"]; diff --git a/src/credentialmodel.cpp b/src/credentialmodel.cpp deleted file mode 100644 index e4cc6a31891e04882e176232f222af8a31b9598e..0000000000000000000000000000000000000000 --- a/src/credentialmodel.cpp +++ /dev/null @@ -1,650 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "credentialmodel.h" - -//Qt -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> -#include <QtCore/QItemSelectionModel> - -//Ring -#include "account.h" -#include "private/matrixutils.h" - -//Dring -#include "dbus/configurationmanager.h" -#include <account_const.h> - -typedef void (CredentialModelPrivate::*CredModelFct)(); - -struct CredentialNode final -{ - Credential* m_pCredential {nullptr}; - CredentialNode* m_pParent {nullptr}; - QString* m_CategoryName {nullptr}; - QVector<CredentialNode*> m_lChildren ; - - enum class Level { - CATEGORY, - CREDENTIAL - }; - - short int m_Index = {-1}; - Level m_Level; -}; - -/** - * Display the types of credentials that can be added - * This depend on the account type and settings - */ -class NewCredentialTypeModel final : public QAbstractListModel -{ - Q_OBJECT - friend class CredentialModel; -public: - explicit NewCredentialTypeModel(Account* a); - virtual ~NewCredentialTypeModel(); - - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - -private: - Account* m_pAccount; - QItemSelectionModel* m_pSelectionModel {nullptr}; - QStringList m_lValues { QStringLiteral("SIP"),QStringLiteral("STUN"),QStringLiteral("TURN")}; - static const Matrix1D<Credential::Type, int> m_smMaximumCount; - static const Matrix2D<Credential::Type, Account::Protocol, bool> m_smAvailableInProtocol; -}; - -class CredentialModelPrivate final -{ -public: - - //Attributes - QList<CredentialNode*> m_lCategories ; - Account* m_pAccount ; - CredentialModel::EditState m_EditState ; - CredentialModel* q_ptr ; - uint m_TopLevelCount = {3}; - static Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> m_mStateMachine; - CredentialNode* m_pSipCat {nullptr}; - CredentialNode* m_pTurnCat {nullptr}; - CredentialNode* m_pStunCat {nullptr}; - NewCredentialTypeModel* m_pTypeModel {nullptr}; - - //Callbacks - void clear (); - void save (); - void reload (); - void nothing(); - void modify (); - - //Helper - inline void performAction(const CredentialModel::EditAction action); - CredentialNode* getCategory(Credential::Type type); - CredentialNode* createCat(const QString& name); -}; - -#define CMP &CredentialModelPrivate -Matrix2D<CredentialModel::EditState, CredentialModel::EditAction,CredModelFct> CredentialModelPrivate::m_mStateMachine ={{ - /* SAVE MODIFY RELOAD CLEAR */ - { CredentialModel::EditState::LOADING , {{ CMP::nothing, CMP::nothing, CMP::reload, CMP::nothing }}}, - { CredentialModel::EditState::READY , {{ CMP::nothing, CMP::modify , CMP::reload, CMP::clear }}}, - { CredentialModel::EditState::MODIFIED , {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}}, - { CredentialModel::EditState::OUTDATED , {{ CMP::save , CMP::nothing, CMP::reload, CMP::clear }}}, -}}; -#undef CMP - -///Constructor -CredentialModel::CredentialModel(Account* acc) : QAbstractItemModel(acc), -d_ptr(new CredentialModelPrivate()) -{ - Q_ASSERT(acc); - d_ptr->m_EditState = CredentialModel::EditState::LOADING; - d_ptr->m_pAccount = acc; - d_ptr->q_ptr = this; - QHash<int, QByteArray> roles = roleNames(); - this << EditAction::RELOAD; - d_ptr->m_EditState = CredentialModel::EditState::READY; -} - -CredentialModel::~CredentialModel() -{ - foreach (CredentialNode* data, d_ptr->m_lCategories) { - delete data; - } -} - -QHash<int,QByteArray> CredentialModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles.insert(CredentialModel::Role::NAME ,QByteArray("name")); - roles.insert(CredentialModel::Role::PASSWORD,QByteArray("password")); - roles.insert(CredentialModel::Role::REALM ,QByteArray("realm")); - } - return roles; -} - -///Get the parent index -QModelIndex CredentialModel::parent( const QModelIndex& index) const -{ - if (!index.isValid()) - return QModelIndex(); - - const CredentialNode* node = static_cast<CredentialNode*>(index.internalPointer()); - - if ((!node) || node->m_Level == CredentialNode::Level::CATEGORY) - return QModelIndex(); - - return createIndex(node->m_pParent->m_Index,0,node->m_pParent); -} - -///Get the column count -int CredentialModel::columnCount( const QModelIndex& parent) const -{ - Q_UNUSED(parent) - return 1; -} - -///Create the indexes -QModelIndex CredentialModel::index( int row, int column, const QModelIndex& parent) const -{ - if (column) - return QModelIndex(); - - if (parent.isValid()) { - const CredentialNode* node = static_cast<CredentialNode*>(parent.internalPointer()); - - if (node->m_Level != CredentialNode::Level::CATEGORY - || row >= node->m_lChildren.size()) - return QModelIndex(); - - return createIndex(row, column, node->m_lChildren.at(row)); - } - - if (row >= d_ptr->m_lCategories.size()) - return QModelIndex(); - - return createIndex(row, column, d_ptr->m_lCategories[row]); -} - -///Model data -QVariant CredentialModel::data(const QModelIndex& idx, int role) const { - if (!idx.isValid()) - return QVariant(); - - const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer()); - - switch (node->m_Level) { - case CredentialNode::Level::CATEGORY: - switch(role) { - case Qt::DisplayRole: - return *node->m_CategoryName; - } - break; - case CredentialNode::Level::CREDENTIAL: - switch (role) { - case Qt::DisplayRole: - case CredentialModel::Role::NAME: - return node->m_pCredential->username(); - case CredentialModel::Role::PASSWORD: - return node->m_pCredential->password(); - case CredentialModel::Role::REALM: - return node->m_pCredential->realm(); - default: - break; - } - break; - } - return QVariant(); -} - -///Number of credentials -int CredentialModel::rowCount(const QModelIndex& par) const { - if (!par.isValid()) - return d_ptr->m_lCategories.size(); - - const CredentialNode* node = static_cast<CredentialNode*>(par.internalPointer()); - - if (node->m_Level == CredentialNode::Level::CREDENTIAL) - return 0; - - return d_ptr->m_lCategories[par.row()]->m_lChildren.size(); -} - -///Model flags -Qt::ItemFlags CredentialModel::flags(const QModelIndex& idx) const { - if (!idx.isValid()) - return Qt::NoItemFlags; - - const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer()); - - //Categories cannot be selected - switch (node->m_Level) { - case CredentialNode::Level::CATEGORY: - return Qt::ItemIsEnabled; - case CredentialNode::Level::CREDENTIAL: - return Qt::ItemIsSelectable | Qt::ItemIsEnabled; - //TODO make turn/stun disabled is account doesn't support/disable it - } - - return Qt::NoItemFlags; -} - -///Set credential data -bool CredentialModel::setData( const QModelIndex& idx, const QVariant &value, int role) { - if (!idx.isValid()) - return false; - - const CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer()); - - if (node->m_Level == CredentialNode::Level::CATEGORY) - return false; - - if (idx.column() == 0 && role == CredentialModel::Role::NAME) { - node->m_pCredential->setUsername(value.toString()); - emit dataChanged(idx, idx); - this << EditAction::MODIFY; - return true; - } - else if (idx.column() == 0 && role == CredentialModel::Role::PASSWORD) { - if (node->m_pCredential->password() != value.toString()) { - node->m_pCredential->setPassword(value.toString()); - emit dataChanged(idx, idx); - this << EditAction::MODIFY; - return true; - } - } - else if (idx.column() == 0 && role == CredentialModel::Role::REALM) { - node->m_pCredential->setRealm(value.toString()); - emit dataChanged(idx, idx); - this << EditAction::MODIFY; - return true; - } - return false; -} - -CredentialNode* CredentialModelPrivate::createCat(const QString& name) -{ - CredentialNode* n = new CredentialNode(); - n->m_Level = CredentialNode::Level::CATEGORY; - n->m_Index = q_ptr->rowCount(); - n->m_CategoryName = new QString(name); - - q_ptr->beginInsertRows(QModelIndex(),m_lCategories.size(),0); - m_lCategories << n; - q_ptr->endInsertRows(); - - return n; -} - -CredentialNode* CredentialModelPrivate::getCategory(Credential::Type type) -{ - switch (type) { - case Credential::Type::SIP: - if (!m_pSipCat) - m_pSipCat = createCat(QStringLiteral("SIP")); - return m_pSipCat; - case Credential::Type::TURN: - if (!m_pTurnCat) - m_pTurnCat = createCat(QStringLiteral("TURN")); - return m_pTurnCat; - case Credential::Type::STUN: - if (!m_pStunCat) - m_pStunCat = createCat(QStringLiteral("STUN")); - return m_pStunCat; - case Credential::Type::COUNT__: - break; - } - - return nullptr; -} - -///Use the selectionmodel to get the type -QModelIndex CredentialModel::addCredentials() -{ - Credential::Type type = Credential::Type::SIP; - - if (d_ptr->m_pTypeModel && d_ptr->m_pTypeModel->m_pSelectionModel - && d_ptr->m_pTypeModel->m_pSelectionModel->currentIndex().isValid()) - type = static_cast<Credential::Type>( - d_ptr->m_pTypeModel->m_pSelectionModel->currentIndex().row() - ); - - return addCredentials(type); -} - -///Add a new credential -QModelIndex CredentialModel::addCredentials(Credential::Type type) -{ - CredentialNode* par = d_ptr->getCategory(type); - const int count = par->m_lChildren.size(); - const QModelIndex parIdx = index(par->m_Index,0); - beginInsertRows(parIdx, count, count); - - CredentialNode* node = new CredentialNode(); - node->m_Level = CredentialNode::Level::CREDENTIAL; - node->m_pCredential = new Credential(type); - node->m_pParent = par; - node->m_Index = par->m_lChildren.size(); - par->m_lChildren.append(node); - - connect(node->m_pCredential, &Credential::changed,[this, node, par, type]() { - const QModelIndex parIdx = index(par->m_Index,0); - const QModelIndex idx = index(node->m_Index,0,parIdx); - emit dataChanged(idx, idx); - - if (!node->m_Index) { - Credential* c = node->m_pCredential; - emit primaryCredentialChanged(type, c); - } - }); - - endInsertRows(); - - this << EditAction::MODIFY; - - return index(count, 0, parIdx); -} - -///Remove credential at 'idx' -void CredentialModel::removeCredentials(const QModelIndex& idx) -{ - if (idx.isValid() && idx.parent().isValid()) { - beginRemoveRows(idx.parent(), idx.row(), idx.row()); - - CredentialNode* node = static_cast<CredentialNode*>(idx.internalPointer()); - - for (int i = node->m_Index+1; i < node->m_pParent->m_lChildren.size();i++) { - node->m_pParent->m_lChildren.at(i)->m_Index--; - } - node->m_pParent->m_lChildren.removeAt(node->m_Index); - delete node; - endRemoveRows(); - - this << EditAction::MODIFY; - } - else { - qDebug() << "Failed to remove an invalid credential"; - } -} - -///Remove everything -void CredentialModelPrivate::clear() -{ - q_ptr->beginRemoveRows(QModelIndex(),0,q_ptr->rowCount()); - m_pSipCat = nullptr; - m_pTurnCat = nullptr; - m_pSipCat = nullptr; - foreach(CredentialNode* data2, m_lCategories) { - delete data2; - } - m_lCategories.clear(); - q_ptr->endRemoveRows(); - m_EditState = CredentialModel::EditState::READY; -} - -///Save all credentials -void CredentialModelPrivate::save() -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - //SIP creds - if (m_pSipCat) { - VectorMapStringString toReturn; - - foreach (CredentialNode* n, m_pSipCat->m_lChildren) { - Credential* cred = n->m_pCredential; - - if (cred->username().isEmpty()) - cred->setUsername(m_pAccount->username()); - - if (cred->realm().isEmpty()) - cred->setRealm(QStringLiteral("*")); - - toReturn << MapStringString { - { DRing::Account::ConfProperties::USERNAME, cred->username() }, - { DRing::Account::ConfProperties::PASSWORD, cred->password() }, - { DRing::Account::ConfProperties::REALM , cred->realm () }, - }; - } - configurationManager.setCredentials(m_pAccount->id(),toReturn); - } - - //TURN creds - if (m_pTurnCat) { - foreach (CredentialNode* n, m_pTurnCat->m_lChildren) { - Credential* cred = n->m_pCredential; - - m_pAccount->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER_UNAME , cred->username()); - m_pAccount->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER_PWD , cred->password()); - m_pAccount->setAccountProperty(DRing::Account::ConfProperties::TURN::SERVER_REALM , cred->realm ()); - } - } - - m_EditState = CredentialModel::EditState::READY; -} - -///Reload credentials from DBUS -void CredentialModelPrivate::reload() -{ - if (!m_pAccount->isNew()) { - clear(); - m_EditState = CredentialModel::EditState::LOADING; - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - //SIP - const VectorMapStringString credentials = configurationManager.getCredentials(m_pAccount->id()); - for (int i=0; i < credentials.size(); i++) { - const QModelIndex& idx = q_ptr->addCredentials(Credential::Type::SIP); - q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::USERNAME ],CredentialModel::Role::NAME ); - q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::PASSWORD ],CredentialModel::Role::PASSWORD); - q_ptr->setData(idx,credentials[i][ DRing::Account::ConfProperties::REALM ],CredentialModel::Role::REALM ); - } - - //TURN - const QModelIndex& idx = q_ptr->addCredentials(Credential::Type::TURN); - const QString usern = m_pAccount->accountDetail(DRing::Account::ConfProperties::TURN::SERVER_UNAME); - const QString passw = m_pAccount->accountDetail(DRing::Account::ConfProperties::TURN::SERVER_PWD ); - const QString realm = m_pAccount->accountDetail(DRing::Account::ConfProperties::TURN::SERVER_REALM); - - if (!(usern.isEmpty() && passw.isEmpty() && realm.isEmpty())) { - q_ptr->setData(idx, usern, CredentialModel::Role::NAME ); - q_ptr->setData(idx, passw, CredentialModel::Role::PASSWORD); - q_ptr->setData(idx, realm, CredentialModel::Role::REALM ); - } - } - m_EditState = CredentialModel::EditState::READY; -} - -void CredentialModelPrivate::nothing() -{ - //nothing -} - -void CredentialModelPrivate::modify() -{ - m_EditState = CredentialModel::EditState::MODIFIED; - m_pAccount << Account::EditAction::MODIFY; -} - -void CredentialModelPrivate::performAction(const CredentialModel::EditAction action) -{ - (this->*(m_mStateMachine[m_EditState][action]))(); -} - -/// anAccount << Call::EditAction::SAVE -CredentialModel* CredentialModel::operator<<(CredentialModel::EditAction& action) -{ - performAction(action); - return this; -} - -CredentialModel* operator<<(CredentialModel* a, CredentialModel::EditAction action) -{ - return (!a)?nullptr : (*a) << action; -} - -///Change the current edition state -bool CredentialModel::performAction(const CredentialModel::EditAction action) -{ - CredentialModel::EditState curState = d_ptr->m_EditState; - d_ptr->performAction(action); - return curState != d_ptr->m_EditState; -} - -/* - * Return the primary credential's set of specified type - * @return credential object, new empty one if none existed. - */ -Credential* CredentialModel::primaryCredential(Credential::Type type) -{ - switch(type) { - case Credential::Type::STUN: - if (!d_ptr->m_pStunCat || !d_ptr->m_pStunCat->m_lChildren.size()) - addCredentials(Credential::Type::STUN); - return d_ptr->m_pStunCat->m_lChildren.first()->m_pCredential; - break; - case Credential::Type::TURN: - if (!d_ptr->m_pTurnCat || !d_ptr->m_pTurnCat->m_lChildren.size()) - addCredentials(Credential::Type::TURN); - return d_ptr->m_pTurnCat->m_lChildren.first()->m_pCredential; - break; - case Credential::Type::SIP: - if (!d_ptr->m_pSipCat || !d_ptr->m_pSipCat->m_lChildren.size()) - addCredentials(Credential::Type::SIP); - return d_ptr->m_pSipCat->m_lChildren.first()->m_pCredential; - break; - case Credential::Type::COUNT__: - break; - } - - return nullptr; -} - -/** - * NewCredentialTypeModel - */ - -///Is a credential type available for an account protocol -const Matrix2D<Credential::Type, Account::Protocol, bool> NewCredentialTypeModel::m_smAvailableInProtocol = { - /* SIP RING */ - { Credential::Type::SIP , {{true, false}}}, - { Credential::Type::STUN, {{true, true }}}, - { Credential::Type::TURN, {{true, true }}}, -}; - -///The maximum number of credentials (-1 = inf), this could be protocol dependent -const Matrix1D<Credential::Type, int> NewCredentialTypeModel::m_smMaximumCount = { - { Credential::Type::SIP , -1 }, - { Credential::Type::STUN, 1 }, - { Credential::Type::TURN, 1 }, -}; - -NewCredentialTypeModel::NewCredentialTypeModel(Account* a) : m_pAccount(a) -{ - -} - -NewCredentialTypeModel::~NewCredentialTypeModel() -{} - -QVariant NewCredentialTypeModel::data( const QModelIndex& index, int role ) const -{ - if (!index.isValid()) - return QVariant(); - - switch (role) { - case Qt::DisplayRole: - return m_lValues[index.row()]; - } - - return QVariant(); -} - -int NewCredentialTypeModel::rowCount( const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : m_lValues.size(); -} - -///Only enabled the available types -Qt::ItemFlags NewCredentialTypeModel::flags( const QModelIndex& index ) const -{ - if (!index.isValid()) - return Qt::NoItemFlags; - - const Credential::Type t = static_cast<Credential::Type>(index.row()); - - bool avail = m_smAvailableInProtocol[t][m_pAccount->protocol()]; - -#if 0 //TODO it mostly work, but make development/testing harder, to enable in the last patch - switch(t) { - case Credential::Type::STUN: - avail &= m_pAccount->isSipStunEnabled(); - break; - case Credential::Type::TURN: - avail &= m_pAccount->isTurnEnabled(); - break; - case Credential::Type::SIP: - case Credential::Type::COUNT__: - break; - } -#endif - - return avail ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags; -} - -bool NewCredentialTypeModel::setData( const QModelIndex& index, const QVariant &value, int role ) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QAbstractItemModel* CredentialModel::availableTypeModel() const -{ - if (!d_ptr->m_pTypeModel) - d_ptr->m_pTypeModel = new NewCredentialTypeModel(d_ptr->m_pAccount); - - return d_ptr->m_pTypeModel; -} - -QItemSelectionModel* CredentialModel::availableTypeSelectionModel() const -{ - if (!static_cast<NewCredentialTypeModel*>(availableTypeModel())->m_pSelectionModel) { - d_ptr->m_pTypeModel->m_pSelectionModel = new QItemSelectionModel(d_ptr->m_pTypeModel); - for (int i=0; i < d_ptr->m_pTypeModel->rowCount(); i++) { - const QModelIndex idx = d_ptr->m_pTypeModel->index(i,0); - if (idx.flags() & Qt::ItemIsSelectable) { - d_ptr->m_pTypeModel->m_pSelectionModel->setCurrentIndex(idx, QItemSelectionModel::ClearAndSelect); - break; - } - } - } - - return d_ptr->m_pTypeModel->m_pSelectionModel; -} - -#include <credentialmodel.moc> diff --git a/src/database.cpp b/src/database.cpp index 1cfd2d923b3651fa0cad7a3e68cb72ff45ec0ffa..748a864adf18682371d8c0d6ba12890f85eeb43f 100644 --- a/src/database.cpp +++ b/src/database.cpp @@ -20,6 +20,9 @@ ***************************************************************************/ #include "database.h" +// daemon +#include <account_const.h> + // Qt #include <QObject> #include <QtCore/QDir> @@ -42,14 +45,9 @@ // Lrc for migrations #include "dbus/configurationmanager.h" -#include "person.h" -#include "account.h" -#include "accountmodel.h" -#include "private/vcardutils.h" +#include "vcard.h" #include <account_const.h> -#include <iostream> - namespace lrc { @@ -512,44 +510,51 @@ Database::migrateLocalProfiles() continue; } - auto personProfile = new Person(nullptr); - QList<Account*> accs; - VCardUtils::mapToPerson(personProfile, content.toUtf8(), &accs); - const auto vCard = VCardUtils::toHashMap(content.toUtf8()); - // all accounts have the same profile picture for now. - const auto alias = vCard["FN"]; + const auto vCard = lrc::vCard::utils::toHashMap(content.toUtf8()); + const auto alias = vCard[lrc::vCard::Property::FORMATTED_NAME]; const auto avatar = vCard["PHOTO;ENCODING=BASE64;TYPE=PNG"]; - for (const auto& account: accs) { - if (!account) continue; - auto type = account->protocol() == Account::Protocol::RING ? "RING" : "SIP"; - auto uri = account->username(); - auto accountId = account->id(); - // Remove the ring: from the username because account uri is stored without "ring:" in the database - if (uri.startsWith("ring:")) { - uri = uri.mid(std::string("ring:").size()); - } - if (select("id", "profiles","uri=:uri", {{":uri", uri.toStdString()}}).payloads.empty()) { - insertInto("profiles", - {{":uri", "uri"}, {":alias", "alias"}, - {":photo", "photo"}, {":type", "type"}, - {":status", "status"}}, - {{":uri", uri.toStdString()}, {":alias", alias.toStdString()}, - {":photo", avatar.toStdString()}, {":type", type}, - {":status", "TRUSTED"}}); - auto profileIds = select("id", "profiles","uri=:uri", - {{":uri", uri.toStdString()}}).payloads; - if (!profileIds.empty() && select("profile_id", "profiles_accounts", - "account_id=:account_id AND is_account=:is_account", - {{":account_id", accountId.toStdString()}, - {":is_account", "true"}}).payloads.empty()) { - insertInto("profiles_accounts", - {{":profile_id", "profile_id"}, - {":account_id", "account_id"}, - {":is_account", "is_account"}}, - {{":profile_id", profileIds[0]}, - {":account_id", accountId.toStdString()}, - {":is_account", "true"}}); + + const QStringList accountIds = ConfigurationManager::instance().getAccountList(); + for (auto accountId : accountIds) { + MapStringString account = ConfigurationManager::instance(). + getAccountDetails(accountId.toStdString().c_str()); + auto accountURI = account[DRing::Account::ConfProperties::USERNAME].contains("ring:") ? + account[DRing::Account::ConfProperties::USERNAME] + .toStdString().substr(std::string("ring:").size()) : + account[DRing::Account::ConfProperties::USERNAME].toStdString(); + + for (const auto& accountId: accountIds) { + MapStringString account = ConfigurationManager::instance() + .getAccountDetails(accountId.toStdString().c_str()); + auto type = account[DRing::Account::ConfProperties::TYPE] == "SIP"? "SIP" : "RING"; + + auto uri = account[DRing::Account::ConfProperties::USERNAME].contains("ring:") ? + account[DRing::Account::ConfProperties::USERNAME] + .toStdString().substr(std::string("ring:").size()) : + account[DRing::Account::ConfProperties::USERNAME].toStdString(); + if (select("id", "profiles","uri=:uri", {{":uri", uri}}).payloads.empty()) { + insertInto("profiles", + {{":uri", "uri"}, {":alias", "alias"}, + {":photo", "photo"}, {":type", "type"}, + {":status", "status"}}, + {{":uri", uri}, {":alias", alias.toStdString()}, + {":photo", avatar.toStdString()}, {":type", type}, + {":status", "TRUSTED"}}); + auto profileIds = select("id", "profiles","uri=:uri", + {{":uri", uri}}).payloads; + if (!profileIds.empty() && select("profile_id", "profiles_accounts", + "account_id=:account_id AND is_account=:is_account", + {{":account_id", accountId.toStdString()}, + {":is_account", "true"}}).payloads.empty()) { + insertInto("profiles_accounts", + {{":profile_id", "profile_id"}, + {":account_id", "account_id"}, + {":is_account", "is_account"}}, + {{":profile_id", profileIds[0]}, + {":account_id", accountId.toStdString()}, + {":is_account", "true"}}); + } } } } @@ -574,7 +579,7 @@ Database::migratePeerProfiles() continue; } - const auto vCard = VCardUtils::toHashMap(content.toUtf8()); + const auto vCard = lrc::vCard::utils::toHashMap(content.toUtf8()); auto uri = vCard["TEL;other"]; const auto alias = vCard["FN"]; const auto avatar = vCard["PHOTO;ENCODING=BASE64;TYPE=PNG"]; @@ -626,9 +631,11 @@ Database::migrateTextHistory() if (loadDoc.find("groups") == loadDoc.end()) continue; // Load account auto peersObject = loadDoc["peers"].toArray()[0].toObject(); - auto account = AccountModel::instance().getById(peersObject["accountId"].toString().toUtf8()); - if (!account) continue; - auto accountUri = account->username(); + + MapStringString details = ConfigurationManager::instance().getAccountDetails(peersObject["accountId"].toString()); + if (!details.contains(DRing::Account::ConfProperties::USERNAME)) continue; + + auto accountUri = details[DRing::Account::ConfProperties::USERNAME]; auto isARingContact = accountUri.startsWith("ring:"); if (isARingContact) { accountUri = accountUri.mid(QString("ring:").length()); diff --git a/src/directrenderer.cpp b/src/directrenderer.cpp index e3f10015a3560dab09ff88884c909893fe9ce258..94351572b33af40043a7688b721b278d35e0233a 100644 --- a/src/directrenderer.cpp +++ b/src/directrenderer.cpp @@ -32,8 +32,6 @@ #define CLOCK_REALTIME 0 #endif -#include "private/videorenderermanager.h" -#include "video/resolution.h" #include "private/videorenderer_p.h" #include "videomanager_interface.h" @@ -144,7 +142,7 @@ std::unique_ptr<AVFrame, void(*)(AVFrame*)> Video::DirectRenderer::currentAVFram return std::move(d_ptr->avframe); } -Video::Frame Video::DirectRenderer::currentFrame() const +lrc::api::video::Frame Video::DirectRenderer::currentFrame() const { if (not isRendering()) return {}; @@ -153,7 +151,7 @@ Video::Frame Video::DirectRenderer::currentFrame() const if (not d_ptr->daemonFramePtr_) return {}; - Video::Frame frame; + lrc::api::video::Frame frame; frame.storage = std::move(d_ptr->daemonFramePtr_->storage); frame.ptr = frame.storage.data(); frame.size = frame.storage.size(); diff --git a/src/directrenderer.h b/src/directrenderer.h index 82dbda167e98ec79ad4f440a3f3167c82db43381..ddddcada8ed04960c44c552dd17110c012533c04 100644 --- a/src/directrenderer.h +++ b/src/directrenderer.h @@ -30,9 +30,6 @@ class QMutex; class QTimer; class QThread; -//Ring -#include "video/device.h" - namespace Video { class DirectRendererPrivate; @@ -53,7 +50,7 @@ public: const DRing::SinkTarget& target() const; const DRing::AVSinkTarget& avTarget() const; virtual ColorSpace colorSpace() const override; - virtual Frame currentFrame() const override; + virtual lrc::api::video::Frame currentFrame() const override; virtual std::unique_ptr<AVFrame, void(*)(AVFrame*)> currentAVFrame() const override; public Q_SLOTS: diff --git a/src/extensions/securityevaluationextension.cpp b/src/extensions/securityevaluationextension.cpp deleted file mode 100644 index 8c78e59aa99b1d293bb3dc088a095ac44f6883dc..0000000000000000000000000000000000000000 --- a/src/extensions/securityevaluationextension.cpp +++ /dev/null @@ -1,137 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "securityevaluationextension.h" -#include "collectioninterface.h" -#include "contactmethod.h" -#include "certificate.h" -#include "person.h" -#include "account.h" -#include "call.h" -#include "collectionextensionmodel.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "private/securityevaluationmodel_p.h" - -//Qt -#include <QtCore/QMetaObject> - -//LibStdC++ -#include <utility> - -DECLARE_COLLECTION_EXTENSION(SecurityEvaluationExtension) - -class SecurityEvaluationExtensionPrivate -{ -public: - //Helpers - SecurityEvaluationModel::SecurityLevel checkCertificate(const ItemBase* i); - SecurityEvaluationModel::SecurityLevel checkAccount (const ItemBase* i); -}; - -SecurityEvaluationExtension::SecurityEvaluationExtension(QObject* parent) : - CollectionExtensionInterface(parent), d_ptr(new SecurityEvaluationExtensionPrivate()) -{ - -} - -SecurityEvaluationExtension::~SecurityEvaluationExtension() -{ - delete d_ptr; -} - -QVariant SecurityEvaluationExtension::data(int role) const -{ - Q_UNUSED(role) - - if (role == Qt::DisplayRole) { - return QObject::tr("Security evaluation"); - } - - return QVariant(); -} - -QVariant SecurityEvaluationExtension::securityLevelIcon(const ItemBase* item) const -{ - const SecurityEvaluationModel::SecurityLevel sl = securityLevel(item); - - return GlobalInstances::pixmapManipulator().securityLevelIcon(sl); -} - -SecurityEvaluationModel::SecurityLevel SecurityEvaluationExtension::securityLevel(const ItemBase* item) const -{ - enum Types { - OTHER , - ACCOUNT , - CALL , - CERTIFICATE , - CONTACT_METHOD, - PERSON , - }; - - static QHash<const QMetaObject*, Types> types { - { &Account :: staticMetaObject , ACCOUNT }, - { &Call :: staticMetaObject , CALL }, - { &Certificate :: staticMetaObject , CERTIFICATE }, - { &ContactMethod :: staticMetaObject , CONTACT_METHOD }, - { &Person :: staticMetaObject , PERSON }, - }; - - switch(types[item->metaObject()]) { - case Types::ACCOUNT : - return d_ptr->checkAccount(item); - case Types::CALL : - //TODO check the "live" certificate chain of trust - //TODO check call details IS_SECURE - //TODO mix with the account SecurityLevel - break; - case Types::CERTIFICATE : - return d_ptr->checkCertificate(item); - case Types::CONTACT_METHOD: - break; - case Types::PERSON : - break; - case Types::OTHER : - default: - return SecurityEvaluationModel::SecurityLevel::NONE; - } - - return SecurityEvaluationModel::SecurityLevel::NONE; -} - -SecurityEvaluationModel::SecurityLevel SecurityEvaluationExtensionPrivate::checkCertificate(const ItemBase* i) -{ - const Certificate* c = qobject_cast<const Certificate*>(i); - - if (!c) - return SecurityEvaluationModel::SecurityLevel::NONE; - - const SecurityEvaluationModel::SecurityLevel l = SecurityEvaluationModelPrivate::certificateSecurityLevel(c,true); - - - return l; -} - -SecurityEvaluationModel::SecurityLevel SecurityEvaluationExtensionPrivate::checkAccount(const ItemBase* i) -{ - const Account* a = qobject_cast<const Account*>(i); - - if (!a) - return SecurityEvaluationModel::SecurityLevel::NONE; - - return a->securityEvaluationModel()->securityLevel(); -} diff --git a/src/extensions/securityevaluationextension.h b/src/extensions/securityevaluationextension.h deleted file mode 100644 index 56545ab495f7e82335f91c741be48abe4f81a112..0000000000000000000000000000000000000000 --- a/src/extensions/securityevaluationextension.h +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <collectionextensioninterface.h> -#include <collectionextensionmodel.h> -#include <securityevaluationmodel.h> - -#include <typedefs.h> - -#include <QtCore/QVariant> -#include <QtCore/QModelIndex> - -class CollectionInterface; -class ItemBase; - -class SecurityEvaluationExtensionPrivate; - -class LIB_EXPORT SecurityEvaluationExtension final : public CollectionExtensionInterface -{ - Q_OBJECT - -public: - explicit SecurityEvaluationExtension(QObject* parent); - - virtual QVariant data(int role) const override; - - SecurityEvaluationModel::SecurityLevel securityLevel(const ItemBase* item) const; - QVariant securityLevelIcon(const ItemBase* item) const; - -private: - SecurityEvaluationExtensionPrivate* d_ptr; - virtual ~SecurityEvaluationExtension(); - Q_DECLARE_PRIVATE(SecurityEvaluationExtension) -}; - diff --git a/src/foldercertificatecollection.cpp b/src/foldercertificatecollection.cpp deleted file mode 100644 index 8e275a639bd5d25c6f7e628a1d038e130c4f7768..0000000000000000000000000000000000000000 --- a/src/foldercertificatecollection.cpp +++ /dev/null @@ -1,369 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "foldercertificatecollection.h" - -//Qt -#include <QtCore/QThread> -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QDebug> -#include <QtCore/QMutex> -#include <QtCore/QStandardPaths> -#include <QtCore/QUrl> - -//Ring -#include "certificate.h" -#include "certificatemodel.h" -#include "database.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" - -//Dring -#include "dbus/configurationmanager.h" - -class FallbackLocalCertificateEditor final : public CollectionEditor<Certificate> -{ -public: - FallbackLocalCertificateEditor(CollectionMediator<Certificate>* m, const QString& path); - virtual bool save ( const Certificate* item ) override; - virtual bool remove ( const Certificate* item ) override; - virtual bool edit ( Certificate* item ) override; - virtual bool addNew ( Certificate* item ) override; - virtual bool addExisting( const Certificate* item ) override; - - QVector<Certificate*> m_lItems; - QString m_Path ; - QHash<const Certificate*,QString> m_hPaths; - -private: - virtual QVector<Certificate*> items() const override; -}; - -class BackgroundLoader final : public QThread -{ - Q_OBJECT -public: - BackgroundLoader(FolderCertificateCollection* parent); - - //Attributes - QMutex m_LoaderMutex; - FolderCertificateCollection* m_pCurrentFolder; - QList<FolderCertificateCollection*> m_lFolderQueue; - - //Helpers - QByteArray loadCertificate(const QByteArray& id); - -protected: - virtual void run() override; - -Q_SIGNALS: - void listLoaded(const QList<QByteArray>& list); -}; - -class FolderCertificateCollectionPrivate -{ -public: - - //Attributes - FlagPack<FolderCertificateCollection::Options> m_Flags; - QString m_Path ; - QString m_Name ; - bool m_IsValid ; - FolderCertificateCollection* m_pParent ; - static bool m_sHasFallbackStore; - FolderCertificateCollection* q_ptr ; - static BackgroundLoader* m_spLoader ; - - //Helper - QList<CollectionInterface::Element> getCertificateList(); -}; - -bool FolderCertificateCollectionPrivate::m_sHasFallbackStore = false; -BackgroundLoader* FolderCertificateCollectionPrivate::m_spLoader = nullptr; - -FolderCertificateCollection::FolderCertificateCollection(CollectionMediator<Certificate>* mediator, - const QString& path , - const FlagPack<Options>& options , - const QString& name , - FolderCertificateCollection* p - ) : -CollectionInterface(new FallbackLocalCertificateEditor(mediator,path),p),d_ptr(new FolderCertificateCollectionPrivate()) -{ - d_ptr->q_ptr = this ; - d_ptr->m_Flags = options; - d_ptr->m_Path = path ; - d_ptr->m_Name = name ; - d_ptr->m_pParent = p ; - d_ptr->m_IsValid = true ; - - if (path.isEmpty()) { - d_ptr->m_Path = lrc::Database::getPath()+"/certs/"; - - d_ptr->m_IsValid = !FolderCertificateCollectionPrivate::m_sHasFallbackStore; - - if (!d_ptr->m_IsValid) { - qWarning() << "A fallback certificat store already exist, doing nothing"; - } - - FolderCertificateCollectionPrivate::m_sHasFallbackStore = true; - } - - if (name.isEmpty()) { - d_ptr->m_Name = d_ptr->m_Path; - } -} - -FolderCertificateCollection::~FolderCertificateCollection() -{ - delete d_ptr; -} - -QByteArray BackgroundLoader::loadCertificate(const QByteArray& id) -{ -// QMutexLocker(&this->m_Mutex); - QFile file(id); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Error opening certificate: " << id; - return QByteArray(); - } - - return file.readAll(); -} - -bool FolderCertificateCollection::load() -{ - if (d_ptr->m_IsValid) { - //Load the stored certificates - if (!d_ptr->m_spLoader) { - d_ptr->m_spLoader = new BackgroundLoader(this); - QObject::connect(d_ptr->m_spLoader, SIGNAL(finished()), d_ptr->m_spLoader, SLOT(deleteLater())); - } - - /*if (!loader->isFinished()) - connect(loader,&BackgroundLoader::finished,[loader](){ - delete loader; - });*/ - - d_ptr->m_spLoader->m_lFolderQueue << this; - - if (!d_ptr->m_spLoader->isRunning()) - d_ptr->m_spLoader->start(); - return true; - } - return false; -} - -bool FolderCertificateCollection::reload() -{ - return false; -} - -QList<CollectionInterface::Element> FolderCertificateCollection::listId() const -{ - return d_ptr->getCertificateList(); -} - -bool FolderCertificateCollection::listId(std::function<void(const QList<CollectionInterface::Element>)> callback) const -{ - Q_UNUSED(callback) - return false; -} - -bool FolderCertificateCollection::clear() -{ - return false; -} - -QString FolderCertificateCollection::name() const -{ - return d_ptr->m_Name; -} - -QString FolderCertificateCollection::category() const -{ - return QObject::tr("Certificate"); -} - -QVariant FolderCertificateCollection::icon() const -{ - return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::CERTIFICATE); -} - -bool FolderCertificateCollection::isEnabled() const -{ - return true; -} - -QByteArray FolderCertificateCollection::id() const -{ - return "FolderCertificateCollection"; -} - -FlagPack<CollectionInterface::SupportedFeatures> FolderCertificateCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LISTABLE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::CLEAR | - CollectionInterface::SupportedFeatures::REMOVE | - CollectionInterface::SupportedFeatures::ADD ; -} - - -QUrl FolderCertificateCollection::path() const -{ - return QUrl(d_ptr->m_Path); -} - - -/******************************************************************************* - * * - * Editor * - * * - ******************************************************************************/ - -FallbackLocalCertificateEditor::FallbackLocalCertificateEditor(CollectionMediator<Certificate>* m, const QString& path) : CollectionEditor<Certificate>(m),m_Path(path) -{ - -} - -bool FallbackLocalCertificateEditor::save( const Certificate* item) -{ - Q_UNUSED(item) - /*QMutexLocker(&this->m_Mutex); - QDir dir(m_Path); - - dir.mkdir("certs/"); - - const QString path = "/certs/" + id + ".pem"; - - //There could be a race condition if the loader load while this is saving - if (dir.exists("certs/"+path)) - return QUrl(dir.path() + path); - - QFile file(dir.path() + path); - - if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) { - QTextStream streamFileOut(&file); - streamFileOut << content; - streamFileOut.flush(); - file.close(); - return QUrl(dir.path() + path); - } - - return QUrl();*/ - return false; -} - -bool FallbackLocalCertificateEditor::remove( const Certificate* item) -{ - Q_UNUSED(item) - return false; -} - -bool FallbackLocalCertificateEditor::edit( Certificate* item) -{ - Q_UNUSED(item) - return false; -} - -bool FallbackLocalCertificateEditor::addNew( Certificate* item) -{ - Q_UNUSED(item) - return false; -} - -bool FallbackLocalCertificateEditor::addExisting( const Certificate* item) -{ - Q_UNUSED(item) - m_lItems << const_cast<Certificate*>(item); - return false; -} - -QVector<Certificate*> FallbackLocalCertificateEditor::items() const -{ - return m_lItems; -} - - -/******************************************************************************* - * * - * Async loader * - * * - ******************************************************************************/ - -BackgroundLoader::BackgroundLoader(FolderCertificateCollection* parent) : QThread(nullptr), -m_pCurrentFolder(parent) -{ - -} - -QList<CollectionInterface::Element> FolderCertificateCollectionPrivate::getCertificateList() -{ -// QMutexLocker(&this->m_Mutex); - QDir dir(m_Path); - - if (!dir.exists()) - return QList<QByteArray>(); - - QList<QByteArray> ret; - for (const QString& str : dir.entryList({"*.pem","*.crt"}) ) { - ret << (m_Path + "/" + str).toLatin1(); - } - - if (m_Flags & FolderCertificateCollection::Options::RECURSIVE) { - for (const QString& d : dir.entryList(QDir::AllDirs)) { - if (d != QString('.') && d != "..") { - CertificateModel::instance().addCollection<FolderCertificateCollection,QString,FlagPack<FolderCertificateCollection::Options>,QString,FolderCertificateCollection*>( - m_Path+'/'+d , - m_Flags , - d , - q_ptr , - LoadOptions::FORCE_ENABLED - ); - } - } - } - - return ret; -} - -void BackgroundLoader::run() -{ - while (m_lFolderQueue.size()) { - m_pCurrentFolder = m_lFolderQueue.takeFirst(); - - QMutexLocker(&this->m_LoaderMutex); - for(const QByteArray& id : m_pCurrentFolder->listId()) { - Certificate* cert = CertificateModel::instance().getCertificateFromPath(id); - m_pCurrentFolder->editor<Certificate>()->addExisting(cert); - - if (m_pCurrentFolder->d_ptr->m_Flags & FolderCertificateCollection::Options::ROOT) - cert->addOrigin(Certificate::OriginHint::ROOT_AUTORITY); - } - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - //qDebug() << "\n\nPINING PATH TODO remove extra /" << m_pCurrentFolder->path(); - configurationManager.pinCertificatePath(m_pCurrentFolder->path().path()+'/'); - } - FolderCertificateCollectionPrivate::m_spLoader = nullptr; - QThread::exit(0); -} - -#include "foldercertificatecollection.moc" diff --git a/src/globalinstances.cpp b/src/globalinstances.cpp index f245516094bfbdafab9ade064e5b13baff1c2f28..fe4dc9cef14f00186623ef43b8cf784464c5b462 100644 --- a/src/globalinstances.cpp +++ b/src/globalinstances.cpp @@ -19,25 +19,18 @@ #include <memory> -#include "interfaces/contactmethodselectori.h" #include "interfaces/dbuserrorhandleri.h" -#include "interfaces/itemmodelstateserializeri.h" #include "interfaces/pixmapmanipulatori.h" -#include "interfaces/shortcutcreatori.h" #include "dbuserrorhandlerdefault.h" #include "pixmapmanipulatordefault.h" -#include "shortcutcreatordefault.h" namespace GlobalInstances { struct InstanceManager { - std::unique_ptr<Interfaces::ContactMethodSelectorI> m_contactMethodSelector; std::unique_ptr<Interfaces::DBusErrorHandlerI> m_dBusErrorHandler; - std::unique_ptr<Interfaces::ItemModelStateSerializerI> m_itemModelStateSerializer; std::unique_ptr<Interfaces::PixmapManipulatorI> m_pixmapManipulator; - std::unique_ptr<Interfaces::ShortcutCreatorI> m_shortcutCreator; }; static InstanceManager& @@ -50,24 +43,7 @@ instanceManager() * LRC does not provide a default implementation of this interface, thus an exception will be thrown * if this getter is called without an instance being set by the client */ -Interfaces::ContactMethodSelectorI& -contactMethodSelector() -{ - if (!instanceManager().m_contactMethodSelector) - throw "no instance of ContactMethodSelector available"; - return *instanceManager().m_contactMethodSelector.get(); -} -void -setContactMethodSelector(std::unique_ptr<Interfaces::ContactMethodSelectorI> instance) -{ - // do not allow empty pointers - if (!instance) { - qWarning() << "ignoring empty unique_ptr"; - return; - } - instanceManager().m_contactMethodSelector = std::move(instance); -} Interfaces::DBusErrorHandlerI& dBusErrorHandler() @@ -92,24 +68,8 @@ setDBusErrorHandler(std::unique_ptr<Interfaces::DBusErrorHandlerI> instance) * LRC does not provide a default implementation of this interface, thus an exception will be thrown * if this getter is called without an instance being set by the client */ -Interfaces::ItemModelStateSerializerI& -itemModelStateSerializer() -{ - if (!instanceManager().m_itemModelStateSerializer) - throw "no instance of ItemModelStateSerializer available"; - return *instanceManager().m_itemModelStateSerializer.get(); -} -void -setItemModelStateSerializer(std::unique_ptr<Interfaces::ItemModelStateSerializerI> instance) -{ - // do not allow empty pointers - if (!instance) { - qWarning() << "ignoring empty unique_ptr"; - return; - } - instanceManager().m_itemModelStateSerializer = std::move(instance); -} + Interfaces::PixmapManipulatorI& pixmapManipulator() @@ -130,26 +90,6 @@ setPixmapManipulator(std::unique_ptr<Interfaces::PixmapManipulatorI> instance) instanceManager().m_pixmapManipulator = std::move(instance); } -Interfaces::ShortcutCreatorI& -shortcutCreator() -{ - if (!instanceManager().m_shortcutCreator) - instanceManager().m_shortcutCreator.reset(new Interfaces::ShortcutCreatorDefault); - return *instanceManager().m_shortcutCreator.get(); -} - -void -setShortcutCreator(std::unique_ptr<Interfaces::ShortcutCreatorI> instance) -{ - // do not allow empty pointers - if (!instance) { - qWarning() << "ignoring empty unique_ptr"; - return; - } - instanceManager().m_shortcutCreator = std::move(instance); -} - - /* * This API have some advantage over a more "explicit" one * 1) It treat interfaces as class instead of as objects, making conceptual sense @@ -170,11 +110,8 @@ void setInterfaceInternal(I* i)\ #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wmissing-declarations" -REGISTER_INTERFACE(Interfaces::ContactMethodSelectorI , m_contactMethodSelector ) REGISTER_INTERFACE(Interfaces::DBusErrorHandlerI , m_dBusErrorHandler ) -REGISTER_INTERFACE(Interfaces::ItemModelStateSerializerI, m_itemModelStateSerializer) REGISTER_INTERFACE(Interfaces::PixmapManipulatorI , m_pixmapManipulator ) -REGISTER_INTERFACE(Interfaces::ShortcutCreatorI , m_shortcutCreator ) #pragma GCC diagnostic pop diff --git a/src/globalinstances.h b/src/globalinstances.h index dd54dfb719787c105a9a5c7ba73bbf3d41d03e0a..b88f9fd55b8bdc259dad934317c92fa3be8c9f48 100644 --- a/src/globalinstances.h +++ b/src/globalinstances.h @@ -24,7 +24,6 @@ namespace Interfaces { class ContactMethodSelectorI; class DBusErrorHandlerI; -class ItemModelStateSerializerI; class PixmapManipulatorI; class ShortcutCreatorI; } // namespace Interfaces @@ -43,8 +42,6 @@ namespace GlobalInstances { * LRC does not provide a default implementation of this interface, thus an exception will be thrown * if this getter is called without an instance being set by the client */ -LIB_EXPORT Interfaces::ContactMethodSelectorI& contactMethodSelector(); -void LIB_EXPORT setContactMethodSelector(std::unique_ptr<Interfaces::ContactMethodSelectorI> instance); Interfaces::DBusErrorHandlerI& dBusErrorHandler(); void setDBusErrorHandler(std::unique_ptr<Interfaces::DBusErrorHandlerI> instance); @@ -53,8 +50,6 @@ void setDBusErrorHandler(std::unique_ptr<Interfaces::DBusErrorHandlerI> instance * LRC does not provide a default implementation of this interface, thus an exception will be thrown * if this getter is called without an instance being set by the client */ -LIB_EXPORT Interfaces::ItemModelStateSerializerI& itemModelStateSerializer(); -void LIB_EXPORT setItemModelStateSerializer(std::unique_ptr<Interfaces::ItemModelStateSerializerI> instance); LIB_EXPORT Interfaces::PixmapManipulatorI& pixmapManipulator(); void LIB_EXPORT setPixmapManipulator(std::unique_ptr<Interfaces::PixmapManipulatorI> instance); @@ -66,7 +61,6 @@ void LIB_EXPORT setShortcutCreator(std::unique_ptr<Interfaces::ShortcutCreatorI> //Private use only void setInterfaceInternal(Interfaces::ContactMethodSelectorI *); void setInterfaceInternal(Interfaces::DBusErrorHandlerI *); -void setInterfaceInternal(Interfaces::ItemModelStateSerializerI*); void setInterfaceInternal(Interfaces::PixmapManipulatorI *); void setInterfaceInternal(Interfaces::ShortcutCreatorI *); diff --git a/src/historytimecategorymodel.cpp b/src/historytimecategorymodel.cpp deleted file mode 100644 index ab5bfc866309f774204e7896b79df9f5896ef89f..0000000000000000000000000000000000000000 --- a/src/historytimecategorymodel.cpp +++ /dev/null @@ -1,195 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "historytimecategorymodel.h" - -#include <QtCore/QDate> -#include <time.h> - -#ifdef _MSC_VER -struct tm *localtime_r(const time_t *_clock, struct tm *_result) -{ - struct tm *p = localtime(_clock); - if (p) - *(_result) = *p; - return p; -} -#endif - -class HistoryTimeCategoryModelPrivate -{ -public: - QVector<QString> m_lCategories; - static HistoryTimeCategoryModel& instance(); -}; - -HistoryTimeCategoryModel& HistoryTimeCategoryModelPrivate::instance() -{ - static auto instance = new HistoryTimeCategoryModel(); - return *instance; -} - -HistoryTimeCategoryModel::HistoryTimeCategoryModel(QObject* parent) : QAbstractListModel(parent), -d_ptr(new HistoryTimeCategoryModelPrivate) -{ - d_ptr->m_lCategories << tr("Today") ;//0 - d_ptr->m_lCategories << tr("Yesterday") ;//1 - d_ptr->m_lCategories << QDate::currentDate().addDays(-2).toString("dddd");//2 - d_ptr->m_lCategories << QDate::currentDate().addDays(-3).toString("dddd");//3 - d_ptr->m_lCategories << QDate::currentDate().addDays(-4).toString("dddd");//4 - d_ptr->m_lCategories << QDate::currentDate().addDays(-5).toString("dddd");//5 - d_ptr->m_lCategories << QDate::currentDate().addDays(-6).toString("dddd");//6 - d_ptr->m_lCategories << tr("A week ago") ;//7 - d_ptr->m_lCategories << tr("Two weeks ago") ;//8 - d_ptr->m_lCategories << tr("Three weeks ago") ;//9 - d_ptr->m_lCategories << tr("A month ago") ;//10 - d_ptr->m_lCategories << tr("Two months ago") ;//11 - d_ptr->m_lCategories << tr("Three months ago") ;//12 - d_ptr->m_lCategories << tr("Four months ago") ;//13 - d_ptr->m_lCategories << tr("Five months ago") ;//14 - d_ptr->m_lCategories << tr("Six months ago") ;//15 - d_ptr->m_lCategories << tr("Seven months ago") ;//16 - d_ptr->m_lCategories << tr("Eight months ago") ;//17 - d_ptr->m_lCategories << tr("Nine months ago") ;//18 - d_ptr->m_lCategories << tr("Ten months ago") ;//19 - d_ptr->m_lCategories << tr("Eleven months ago") ;//20 - d_ptr->m_lCategories << tr("Twelve months ago") ;//21 - d_ptr->m_lCategories << tr("A year ago") ;//22 - d_ptr->m_lCategories << tr("Very long time ago") ;//23 - d_ptr->m_lCategories << tr("Never") ;//24 -} - -HistoryTimeCategoryModel::~HistoryTimeCategoryModel() -{ - delete d_ptr; -} - -QHash<int,QByteArray> HistoryTimeCategoryModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -//Abstract model member -QVariant HistoryTimeCategoryModel::data(const QModelIndex& index, int role ) const -{ - if (!index.isValid()) return QVariant(); - switch (role) { - case Qt::DisplayRole: - return d_ptr->m_lCategories[index.row()]; - } - return QVariant(); -} - -int HistoryTimeCategoryModel::rowCount(const QModelIndex& parent ) const -{ - if (parent.isValid()) return 0; - return d_ptr->m_lCategories.size(); -} - -Qt::ItemFlags HistoryTimeCategoryModel::flags(const QModelIndex& index ) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -bool HistoryTimeCategoryModel::setData(const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - - -QString HistoryTimeCategoryModel::timeToHistoryCategory(const time_t time) -{ - static int categoriesSize = HistoryTimeCategoryModelPrivate::instance().d_ptr->m_lCategories.size(); - int period = (int)HistoryTimeCategoryModel::timeToHistoryConst(time); - if (period >= 0 && period < categoriesSize) - return HistoryTimeCategoryModelPrivate::instance().d_ptr->m_lCategories[period]; - else - return HistoryTimeCategoryModelPrivate::instance().d_ptr->m_lCategories[categoriesSize - 1]; -} - -HistoryTimeCategoryModel::HistoryConst HistoryTimeCategoryModel::timeToHistoryConst(const time_t time) -{ - if (!time || time < 0) - return HistoryTimeCategoryModel::HistoryConst::Never; - - time_t currentTime; - ::time(¤tTime); - - /* - * Struct tm description of fields used below: - * tm_yday int days since January 1 0-365 - * tm_mon int months since January 0-11 - * tm_year int years since 1900 - * tm_wday int days since Sunday 0-6 - */ - struct tm localCurrentTime; - struct tm localPastTime; - - ::localtime_r(¤tTime, &localCurrentTime); - ::localtime_r(&time, &localPastTime); - - int diffYears = localCurrentTime.tm_year - localPastTime.tm_year; - int diffMonths = localCurrentTime.tm_mon - localPastTime.tm_mon; - int diffDays = localCurrentTime.tm_yday - localPastTime.tm_yday; - - if (diffYears == 1 && diffMonths < 0) { - diffMonths += 12; - diffDays += 365; - diffYears = 0; - } - - //Sanity check for future dates - if (diffYears < 0 || (diffYears == 0 && (diffDays < 0 || diffMonths < 0))) { - return HistoryTimeCategoryModel::HistoryConst::Never; - } - //Check for past 6 days - if (diffYears == 0 && diffDays < 7) { - return (HistoryTimeCategoryModel::HistoryConst)(diffDays); //Today to Six_days_ago - } - //Check for last month - else if (diffYears == 0 && diffMonths <= 1 && (diffDays / 7 <= 4)) { - return (HistoryTimeCategoryModel::HistoryConst)(diffDays / 7 + ((int)HistoryTimeCategoryModel::HistoryConst::A_week_ago) - 1); //A_week_ago to Three_weeks_ago - } - //Check for last year - else if (diffYears == 0 && diffMonths > 0) { - return (HistoryTimeCategoryModel::HistoryConst)(diffMonths + ((int)HistoryTimeCategoryModel::HistoryConst::A_month_ago) - 1); //A_month_ago to Twelve_months ago - } - else if (diffYears == 1) - return HistoryConst::A_year_ago; - - //Every other senario - return HistoryTimeCategoryModel::HistoryConst::Very_long_time_ago; -} - -QString HistoryTimeCategoryModel::indexToName(int idx) -{ - static int size = HistoryTimeCategoryModelPrivate::instance().d_ptr->m_lCategories.size(); - if (idx < 0 || idx >= size) - return HistoryTimeCategoryModelPrivate::instance().d_ptr->m_lCategories.last(); - return HistoryTimeCategoryModelPrivate::instance().d_ptr->m_lCategories[idx]; -} diff --git a/src/hookmanager.cpp b/src/hookmanager.cpp deleted file mode 100644 index 2da4b16e73748359e6bdcdd72fe636ad4dae7eaf..0000000000000000000000000000000000000000 --- a/src/hookmanager.cpp +++ /dev/null @@ -1,133 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "hookmanager.h" - -#include <QtCore/QCoreApplication> -#include "dbus/configurationmanager.h" - -class HookManagerPrivate -{ -public: - void save(); - - class Names { - public: - constexpr static const char* PHONE_NUMBER_HOOK_ADD_PREFIX = "PHONE_NUMBER_HOOK_ADD_PREFIX"; - constexpr static const char* URLHOOK_SIP_FIELD = "URLHOOK_SIP_FIELD" ; - constexpr static const char* URLHOOK_COMMAND = "URLHOOK_COMMAND" ; - constexpr static const char* URLHOOK_SIP_ENABLED = "URLHOOK_SIP_ENABLED" ; - constexpr static const char* PHONE_NUMBER_HOOK_ENABLED = "PHONE_NUMBER_HOOK_ENABLED" ; - }; - - //Attributes - QString m_AddPrefix ; - QString m_SipFeild ; - QString m_Command ; - bool m_SipEnabled ; - bool m_ContactMethodEnabled; -}; - -HookManager::HookManager() : QObject(QCoreApplication::instance()),d_ptr(new HookManagerPrivate()) -{ - ConfigurationManagerInterface & configurationManager = ConfigurationManager::instance(); - QMap<QString,QString> hooks = configurationManager.getHookSettings(); - d_ptr->m_AddPrefix = hooks[HookManagerPrivate::Names::PHONE_NUMBER_HOOK_ADD_PREFIX]; - d_ptr->m_SipFeild = hooks[HookManagerPrivate::Names::URLHOOK_SIP_FIELD ]; - d_ptr->m_Command = hooks[HookManagerPrivate::Names::URLHOOK_COMMAND ]; - d_ptr->m_SipEnabled = hooks[HookManagerPrivate::Names::URLHOOK_SIP_ENABLED ]=="true"?true:false; - d_ptr->m_ContactMethodEnabled = hooks[HookManagerPrivate::Names::PHONE_NUMBER_HOOK_ENABLED ]=="true"?true:false; - -} - -HookManager::~HookManager() -{ -} - -void HookManagerPrivate::save() -{ - ConfigurationManagerInterface & configurationManager = ConfigurationManager::instance(); - QMap<QString,QString> hooks; - - hooks[HookManagerPrivate::Names::PHONE_NUMBER_HOOK_ADD_PREFIX] = m_AddPrefix; - hooks[HookManagerPrivate::Names::URLHOOK_SIP_FIELD ] = m_SipFeild; - hooks[HookManagerPrivate::Names::URLHOOK_COMMAND ] = m_Command; - hooks[HookManagerPrivate::Names::URLHOOK_SIP_ENABLED ] = m_SipEnabled?"true":"false"; - hooks[HookManagerPrivate::Names::PHONE_NUMBER_HOOK_ENABLED ] = m_ContactMethodEnabled?"true":"false"; - configurationManager.setHookSettings(hooks); -} - -HookManager& HookManager::instance() -{ - static auto instance = new HookManager; - return *instance; -} - -QString HookManager::prefix() const -{ - return d_ptr->m_AddPrefix; -} - -QString HookManager::sipFeild() const -{ - return d_ptr->m_SipFeild; -} - -QString HookManager::command() const -{ - return d_ptr->m_Command; -} - -bool HookManager::isSipEnabled() const -{ - return d_ptr->m_SipEnabled; -} - -bool HookManager::isContactMethodEnabled() const -{ - return d_ptr->m_ContactMethodEnabled; -} - -void HookManager::setPrefix(const QString& prefix) -{ - d_ptr->m_AddPrefix = prefix; - d_ptr->save(); -} - -void HookManager::setSipFeild(const QString& field) -{ - d_ptr->m_SipFeild = field; - d_ptr->save(); -} - -void HookManager::setCommand(const QString& command) -{ - d_ptr->m_Command = command; - d_ptr->save(); -} - -void HookManager::setSipEnabled(bool enabled) -{ - d_ptr->m_SipEnabled = enabled; - d_ptr->save(); -} - -void HookManager::setContactMethodEnabled(bool enabled) -{ - d_ptr->m_ContactMethodEnabled = enabled; - d_ptr->save(); -} diff --git a/src/hookmanager.h b/src/hookmanager.h deleted file mode 100644 index 564c9ba2dc76ab79c405c70441bfb82bc6304d61..0000000000000000000000000000000000000000 --- a/src/hookmanager.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" -class HookManagerPrivate; - -/** - * This class allow to get and set the different hooks - */ -class LIB_EXPORT HookManager : public QObject -{ - Q_OBJECT - -public: - static HookManager& instance(); - - //Properties - Q_PROPERTY(QString prefix READ prefix WRITE setPrefix ) - Q_PROPERTY(QString sipFeild READ sipFeild WRITE setSipFeild ) - Q_PROPERTY(QString command READ command WRITE setCommand ) - Q_PROPERTY(bool sipEnabled READ isSipEnabled WRITE setSipEnabled ) - Q_PROPERTY(bool phoneNumberEnabled READ isContactMethodEnabled WRITE setContactMethodEnabled ) - - //Getters - QString prefix () const; - QString sipFeild () const; - QString command () const; - bool isSipEnabled () const; - bool isContactMethodEnabled() const; - - //Setters - void setPrefix (const QString& prefix ); - void setSipFeild (const QString& field ); - void setCommand (const QString& command); - void setSipEnabled (bool enabled ); - void setContactMethodEnabled (bool enabled ); - -private: - explicit HookManager(); - virtual ~HookManager(); - - QScopedPointer<HookManagerPrivate> d_ptr; -}; diff --git a/src/interfaces/contactmethodselectori.h b/src/interfaces/contactmethodselectori.h deleted file mode 100644 index e022041b0c27d84e486261198df5da4cbe3b1cdf..0000000000000000000000000000000000000000 --- a/src/interfaces/contactmethodselectori.h +++ /dev/null @@ -1,36 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -class ContactMethod; -class Person; - -namespace Interfaces { - -///Interface for client (GUI) specific contact dialog -class ContactMethodSelectorI { -public: - virtual ~ContactMethodSelectorI() = default; - - ///Returns the CM chosen to be used to contact the given Person - virtual ContactMethod* number(const Person* p) = 0; -}; - -} // namespace Interfaces diff --git a/src/interfaces/itemmodelstateserializeri.h b/src/interfaces/itemmodelstateserializeri.h deleted file mode 100644 index 0ce3221d88e57adfb3780a55543eca86d70353f4..0000000000000000000000000000000000000000 --- a/src/interfaces/itemmodelstateserializeri.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -// Ring -#include <collectioninterface.h> -class Account; -class CollectionManagerInterfaceBase; - -namespace Interfaces { - -/** - * Interface for tracking and saving/loading the state (enabled or not) of the backends - * (CollectionInterfaces) - */ -class ItemModelStateSerializerI { -public: - /** - * Hints for the preferredCollection implementation about how to select - * the right collection. - */ - enum class Hints { - NONE = 0x0 << 0, - ASK_USER = 0x1 << 0, - DO_NOT_ASK_USER = 0x1 << 1, - }; - - virtual ~ItemModelStateSerializerI() = default; - - /** - * Called when the new enabled collection list need to be serialized - */ - virtual bool save() = 0; - - /** - * Called when the enabled collection list is first needed - * - * @note You can call this manually if your collections depend on it - */ - virtual bool load() = 0; - - //Getter - virtual bool isChecked(const CollectionInterface* backend) const = 0; - - /** - * Allow to overload the default algorithm used to look for a default - * collection to store something new. - * - * @param manager The likes of PersonModel::instance() or CategorizedHistoryModel::instance() - * @param features A list of must have collection features. If NONE is set \ - * the implementation is free to return whatever it want. If it is set, a \ - * collection must return a compliant collection or the result will be \ - * ignored. - */ - virtual CollectionInterface* preferredCollection(CollectionManagerInterfaceBase* manager, - FlagPack<CollectionInterface::SupportedFeatures> features - = FlagPack<CollectionInterface::SupportedFeatures>(CollectionInterface::SupportedFeatures::NONE), - FlagPack<Hints> hints = FlagPack<Hints>(Hints::NONE) - ) = 0; - - //Setter - virtual bool setChecked(const CollectionInterface* backend, bool enabled) = 0; -}; - -} // namespace Interface diff --git a/src/interfaces/pixmapmanipulatori.h b/src/interfaces/pixmapmanipulatori.h index 100562a4b8f9a134e0cc22c929716f2de3ada8e8..ac4f61111f6527b86118d01e871a9936a4000f86 100644 --- a/src/interfaces/pixmapmanipulatori.h +++ b/src/interfaces/pixmapmanipulatori.h @@ -25,13 +25,6 @@ class QModelIndex; class QByteArray ; //Ring -#include <securityevaluationmodel.h> - -class Person ; -class ContactMethod ; -class Call ; -class CollectionInterface; -class Account; struct UserActionElement ; namespace lrc { namespace api { @@ -69,9 +62,6 @@ public: virtual ~PixmapManipulatorI() = default; - virtual QVariant contactPhoto(Person* c, const QSize& size, bool displayPresence = true) = 0; - virtual QVariant callPhoto(Call* c, const QSize& size, bool displayPresence = true) = 0; - virtual QVariant callPhoto(const ContactMethod* n, const QSize& size, bool displayPresence = true) = 0; virtual QVariant conversationPhoto(const lrc::api::conversation::Info& conversation, const lrc::api::account::Info& accountInfo, const QSize& size, @@ -80,21 +70,14 @@ public: return {}; } virtual QVariant numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence = false, bool isPresent = false) = 0; - virtual QVariant securityIssueIcon(const QModelIndex& index) = 0; virtual QByteArray toByteArray(const QVariant& pxm) = 0; virtual QVariant personPhoto(const QByteArray& data, const QString& type = "PNG") = 0; - virtual QVariant collectionIcon(const CollectionInterface* colItf, PixmapManipulatorI::CollectionIconHint hint = PixmapManipulatorI::CollectionIconHint::NONE) const = 0; - virtual QVariant securityLevelIcon(const SecurityEvaluationModel::SecurityLevel level) const = 0; virtual QVariant decorationRole(const QModelIndex& index) = 0; - virtual QVariant decorationRole(const Call* c ) = 0; - virtual QVariant decorationRole(const ContactMethod* cm ) = 0; - virtual QVariant decorationRole(const Person* p ) = 0; virtual QVariant decorationRole(const lrc::api::conversation::Info& conversation, const lrc::api::account::Info& accountInfo) { Q_UNUSED(conversation); Q_UNUSED(accountInfo); return {}; } - virtual QVariant decorationRole(const Account* acc ) = 0; /** * Return the icons associated with the action and its state diff --git a/src/interfaces/shortcutcreatori.h b/src/interfaces/shortcutcreatori.h deleted file mode 100644 index 706506468c9056fb554a88eb0089b30f1e7c5e32..0000000000000000000000000000000000000000 --- a/src/interfaces/shortcutcreatori.h +++ /dev/null @@ -1,41 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -//Qt -// #include <QtCore/QVariant> -class QVariant; - -//Ring -class Macro; - -namespace Interfaces { - -/** - * Interface for attaching a QAction/GAction/MASShortcut to a Macro - */ -class ShortcutCreatorI { -public: - virtual ~ShortcutCreatorI() = default; - - virtual QVariant createAction(Macro* macro) = 0; -}; - -} // namespace Interfaces diff --git a/src/itembase.cpp b/src/itembase.cpp deleted file mode 100644 index 9caeac25bc89cb87ba79cb7b4e03f2913551d886..0000000000000000000000000000000000000000 --- a/src/itembase.cpp +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "itembase.h" - -ItemBase::ItemBase(QObject* parent) :QObject(nullptr), d_ptr(new ItemBasePrivate()) -{ - QObject::moveToThread(QCoreApplication::instance()->thread()); - QObject::setParent(parent); -} - -ItemBase::~ItemBase() -{ - delete d_ptr; -} - -CollectionInterface* ItemBase::collection() const -{ - return d_ptr->m_pBackend; -} - -void ItemBase::setCollection(CollectionInterface* backend) -{ - Q_ASSERT(backend->metaObject()->className() == this->metaObject()->className() - || inherits(backend->metaObject()->className()) - ); - d_ptr->m_pBackend = backend; -} - -///Save the contact -bool ItemBase::save() const -{ - if (!d_ptr->m_pBackend) - return false; - - return d_ptr->m_pBackend->save(this); -} - -///Show an implementation dependent dialog to edit the contact -bool ItemBase::edit() -{ - if (!d_ptr->m_pBackend) - return false; - - return d_ptr->m_pBackend->edit(this); -} - -///Remove the contact from the backend -bool ItemBase::remove() -{ - if (!d_ptr->m_pBackend) - return false; - - return d_ptr->m_pBackend->remove(this); -} - -bool ItemBase::isActive() const -{ - return d_ptr->m_pBackend->isEnabled() && d_ptr->m_isActive; -} \ No newline at end of file diff --git a/src/itembase.h b/src/itembase.h deleted file mode 100644 index ccdfeb197add0c32ae2e5bc5cdf5179c3de48e35..0000000000000000000000000000000000000000 --- a/src/itembase.h +++ /dev/null @@ -1,60 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -#include <collectioninterface.h> - -class ItemBasePrivate; - -/** - * Base class for all items to be managed in CollectionInterface - */ -class LIB_EXPORT ItemBase : public QObject -{ - Q_OBJECT - - friend class CollectionInterface; -public: - //Constructor - explicit ItemBase(QObject* parent = nullptr); - virtual ~ItemBase(); - virtual CollectionInterface* collection() const final; - - //Extension system - template<typename T2> - bool hasExtenstion() const; - - template<typename T2> - T2* extension() const; - - //Mutator methods - Q_INVOKABLE bool save () const; - Q_INVOKABLE bool edit () ; - Q_INVOKABLE bool remove () ; - Q_INVOKABLE bool isActive() const; - - //Setter - void setCollection(CollectionInterface* backend); - -private: - ItemBasePrivate* d_ptr; -}; - -#include <itembase.hpp> diff --git a/src/itembase.hpp b/src/itembase.hpp deleted file mode 100644 index cfa2ed25e68728825f5f1db8458d6b6646d626a0..0000000000000000000000000000000000000000 --- a/src/itembase.hpp +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "collectioninterface.h" -#include "collectioneditor.h" -#include <QtCore/QObject> -#include <QtCore/QMetaObject> -#include <QtCore/QCoreApplication> - -class ItemBasePrivate -{ -public: - ItemBasePrivate() : m_pBackend(nullptr),m_isActive(true){} - CollectionInterface* m_pBackend; - bool m_isActive; -}; - -template<typename T2> -bool ItemBase::hasExtenstion() const -{ - if (!d_ptr->m_pBackend) - return false; - - return d_ptr->m_pBackend->isExtensionActive<T2>(); -} - -template<typename T2> -T2* ItemBase::extension() const -{ - if (!d_ptr->m_pBackend) - return CollectionExtensionModel::getExtension<T2>();; - - return d_ptr->m_pBackend->extension<T2>(); -} diff --git a/src/itemdataroles.h b/src/itemdataroles.h deleted file mode 100644 index 5009282fe5642338b9cbeca82777576c0c00c26c..0000000000000000000000000000000000000000 --- a/src/itemdataroles.h +++ /dev/null @@ -1,72 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -namespace Ring { - -/** - * The purpose of this enum class is to mimic/extend the Qt::ItemDataRole in LRC so that the same - * value is used when using a common role in the ::data() method of any model in LRC, - * eg: the value of the Object role should not be different for the PersonModel and the CallModel. - * - * This is so that clients of LRC do need additional logic when trying to extract the same type of - * data from multiple types of LRC models. - * - * Thus any data role which is common to multiple models in LRC should be defined here. Data roles - * which are specific to the model can be defined within that model only and their value should - * start with UserRole + 1 - */ - -enum class Role -{ - DisplayRole = Qt::DisplayRole , - Object = Qt::UserRole + 1, - ObjectType , - Name , - Number , - LastUsed , - FormattedLastUsed , - IndexedLastUsed , - State , - FormattedState , - Length , - DropState , - IsPresent , - UnreadTextMessageCount, - URI , - UserRole = Qt::UserRole + 100 // this should always be the last role in the list -}; - -/** - * All LRC models that store more than one type of class (eg: RecentModel) should return a member of - * this enum when ::data(Ring::Role::ObjectType) is called on one of their indeces. This is to - * simplify LRC and client logic by not having to dynamic_cast the pointer stored in the index. - */ -enum class ObjectType -{ - Person, - ContactMethod, - Call, - Media, - Certificate, - COUNT__ -}; - -} // namespace Ring - -Q_DECLARE_METATYPE(Ring::ObjectType) diff --git a/src/keyexchangemodel.cpp b/src/keyexchangemodel.cpp deleted file mode 100644 index c50d58e2d3214afb350b895abd8297a437b0075b..0000000000000000000000000000000000000000 --- a/src/keyexchangemodel.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "keyexchangemodel.h" - -//Qt -#include <QtCore/QCoreApplication> -#include <QtCore/QItemSelectionModel> - -//Ring daemon -#include <account_const.h> - -//Ring -#include "account.h" -#include "private/matrixutils.h" - -class KeyExchangeModelPrivate final : public QObject -{ - Q_OBJECT -public: - - class Name { - public: - constexpr static const char* NONE = "None"; - constexpr static const char* SDES = "SDES"; - }; - - class DaemonName { - public: - constexpr static const char* NONE = "" ; - constexpr static const char* SDES = "sdes"; - }; - - KeyExchangeModelPrivate(KeyExchangeModel* parent); - - //Attributes - Account* m_pAccount; - QItemSelectionModel* m_pSelectionModel; - - //Getters - QModelIndex toIndex (KeyExchangeModel::Type type) const; - static const char* toDaemonName (KeyExchangeModel::Type type) ; - static KeyExchangeModel::Type fromDaemonName(const QString& name ) ; - - - //Helper - void setKeyExchange(KeyExchangeModel::Type detail); - KeyExchangeModel::Type keyExchange() const; - -public Q_SLOTS: - void slotCurrentIndexChanged(const QModelIndex& idx, const QModelIndex& prev); - -private: - KeyExchangeModel* q_ptr; -}; - -KeyExchangeModelPrivate::KeyExchangeModelPrivate(KeyExchangeModel* parent) : QObject(parent), q_ptr(parent),m_pAccount(nullptr), m_pSelectionModel(nullptr) -{ -} - -KeyExchangeModel::KeyExchangeModel(Account* account) : QAbstractListModel(account),d_ptr(new KeyExchangeModelPrivate(this)) -{ - d_ptr->m_pAccount = account; -} - -KeyExchangeModel::~KeyExchangeModel() -{ -// delete d_ptr; -} - -QHash<int,QByteArray> KeyExchangeModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - roles[static_cast<int>(KeyExchangeModel::Role::TYPE)] = "type"; - initRoles = true; - - } - return roles; -} - -//Model functions -QVariant KeyExchangeModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) return QVariant(); - KeyExchangeModel::Type method = static_cast<KeyExchangeModel::Type>(index.row()); - if (role == Qt::DisplayRole) { - switch (method) { - case KeyExchangeModel::Type::NONE: - return KeyExchangeModelPrivate::Name::NONE; - case KeyExchangeModel::Type::SDES: - return KeyExchangeModelPrivate::Name::SDES; - case KeyExchangeModel::Type::COUNT__: - break; - }; - } - else if (role == static_cast<int>(KeyExchangeModel::Role::TYPE)) - return QVariant::fromValue(method); - - return QVariant(); -} - -int KeyExchangeModel::rowCount( const QModelIndex& parent ) const -{ - return parent.isValid()?0:2; -} - -bool KeyExchangeModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role ) - return false; -} - -///Translate enum type to QModelIndex -QModelIndex KeyExchangeModelPrivate::toIndex(KeyExchangeModel::Type type) const -{ - return q_ptr->index(static_cast<int>(type),0,QModelIndex()); -} - -///Translate enum to daemon name -const char* KeyExchangeModelPrivate::toDaemonName(KeyExchangeModel::Type type) -{ - switch (type) { - case KeyExchangeModel::Type::NONE: - return KeyExchangeModelPrivate::DaemonName::NONE; - case KeyExchangeModel::Type::SDES: - return KeyExchangeModelPrivate::DaemonName::SDES; - case KeyExchangeModel::Type::COUNT__: - break; - }; - return nullptr; //Cannot heppen -} - -KeyExchangeModel::Type KeyExchangeModelPrivate::fromDaemonName(const QString& name) -{ - if (name.isEmpty()) - return KeyExchangeModel::Type::NONE; - else if (name == KeyExchangeModelPrivate::DaemonName::SDES) - return KeyExchangeModel::Type::SDES; - qDebug() << "Undefined Key exchange mechanism" << name; - return KeyExchangeModel::Type::NONE; -} - -void KeyExchangeModel::enableSRTP(bool enable) -{ - if (enable && d_ptr->keyExchange() == KeyExchangeModel::Type::NONE) { - d_ptr->setKeyExchange(KeyExchangeModel::Type::SDES); - } - else if (!enable) { - d_ptr->setKeyExchange(KeyExchangeModel::Type::NONE); - } -} - -QItemSelectionModel* KeyExchangeModel::selectionModel() const -{ - if (!d_ptr->m_pSelectionModel) { - d_ptr->m_pSelectionModel = new QItemSelectionModel(const_cast<KeyExchangeModel*>(this)); - const KeyExchangeModel::Type current = d_ptr->keyExchange(); - d_ptr->m_pSelectionModel->setCurrentIndex(d_ptr->toIndex(current), QItemSelectionModel::ClearAndSelect); - - connect(d_ptr->m_pSelectionModel, &QItemSelectionModel::currentChanged, d_ptr.data(), &KeyExchangeModelPrivate::slotCurrentIndexChanged); - } - - return d_ptr->m_pSelectionModel; -} - -void KeyExchangeModelPrivate::slotCurrentIndexChanged(const QModelIndex& idx, const QModelIndex& prev) -{ - Q_UNUSED(prev) - - if (!idx.isValid()) - return; - - const KeyExchangeModel::Type t = static_cast<KeyExchangeModel::Type>(idx.row()); - setKeyExchange(t); -} - -///Return the key exchange mechanism -KeyExchangeModel::Type KeyExchangeModelPrivate::keyExchange() const -{ - return KeyExchangeModelPrivate::fromDaemonName(m_pAccount->accountDetail(DRing::Account::ConfProperties::SRTP::KEY_EXCHANGE)); -} - -///Set the Tls method -void KeyExchangeModelPrivate::setKeyExchange(KeyExchangeModel::Type detail) -{ - m_pAccount->setAccountProperty(DRing::Account::ConfProperties::SRTP::KEY_EXCHANGE ,KeyExchangeModelPrivate::toDaemonName(detail)); - m_pAccount->regenSecurityValidation(); -} - -#include <keyexchangemodel.moc> diff --git a/src/keyexchangemodel.h b/src/keyexchangemodel.h deleted file mode 100644 index 26866d38f41413acb4f12ebac3b0f51997dec728..0000000000000000000000000000000000000000 --- a/src/keyexchangemodel.h +++ /dev/null @@ -1,80 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" -#include <QtCore/QAbstractListModel> - -//Qt -class QItemSelectionModel; - -//Ring -class Account; -class KeyExchangeModelPrivate; - -///Static model for handling encryption types -class LIB_EXPORT KeyExchangeModel : public QAbstractListModel { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - friend class Account; - -public: - - enum class Role { - TYPE = 100 - }; - - ///@enum Type Every supported encryption types - enum class Type { - NONE = 0, - SDES = 1, - COUNT__, - }; - - ///@enum Options Every Key exchange options - enum class Options { - RTP_FALLBACK = 0, - COUNT__, - }; - - //Private constructor, can only be called by 'Account' - explicit KeyExchangeModel(Account* account); - virtual ~KeyExchangeModel(); - - //Model functions - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - QItemSelectionModel* selectionModel() const; - -private: - QScopedPointer<KeyExchangeModelPrivate> d_ptr; - -public Q_SLOTS: - void enableSRTP(bool enable); - -Q_SIGNALS: - void srtpEnabled(bool); -}; -Q_DECLARE_METATYPE(KeyExchangeModel*) -Q_DECLARE_METATYPE(KeyExchangeModel::Type) - diff --git a/src/localhistorycollection.cpp b/src/localhistorycollection.cpp deleted file mode 100644 index 25654a2461ea4f423160553c8183b35b19fed9b9..0000000000000000000000000000000000000000 --- a/src/localhistorycollection.cpp +++ /dev/null @@ -1,284 +0,0 @@ -/************************************************************************************ - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the GNU Lesser General Public * - * License along with this library; if not, write to the Free Software * - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***********************************************************************************/ -#include "localhistorycollection.h" - -//Qt -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QHash> -#include <QtCore/QStandardPaths> -#include <QtCore/QStandardPaths> -#include <QtCore/QUrl> - -//Ring -#include "call.h" -#include "database.h" -#include "media/media.h" -#include "media/recording.h" -#include "media/avrecording.h" -#include "account.h" -#include "person.h" -#include "certificate.h" -#include "contactmethod.h" -#include "categorizedhistorymodel.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" - -class LocalHistoryEditor final : public CollectionEditor<Call> -{ -public: - LocalHistoryEditor(CollectionMediator<Call>* m, LocalHistoryCollection* parent); - virtual bool save ( const Call* item ) override; - virtual bool remove ( const Call* item ) override; - virtual bool edit ( Call* item ) override; - virtual bool addNew ( Call* item ) override; - virtual bool addExisting( const Call* item ) override; - -private: - virtual QVector<Call*> items() const override; - - //Helpers - void saveCall(QTextStream& stream, const Call* call); - bool regenFile(const Call* toIgnore); - - //Attributes - QVector<Call*> m_lItems; - LocalHistoryCollection* m_pCollection; -}; - -LocalHistoryEditor::LocalHistoryEditor(CollectionMediator<Call>* m, LocalHistoryCollection* parent) : -CollectionEditor<Call>(m),m_pCollection(parent) -{ - -} - -LocalHistoryCollection::LocalHistoryCollection(CollectionMediator<Call>* mediator) : -CollectionInterface(new LocalHistoryEditor(mediator,this)),m_pMediator(mediator) -{ -// setObjectName("LocalHistoryCollection"); -} - -LocalHistoryCollection::~LocalHistoryCollection() -{ - -} - -void LocalHistoryEditor::saveCall(QTextStream& stream, const Call* call) -{ - if (!CategorizedHistoryModel::instance().isHistoryEnabled()) - return; - - stream.setCodec("UTF-8"); - const QString direction = (call->direction()==Call::Direction::INCOMING)? - Call::HistoryStateName::INCOMING : Call::HistoryStateName::OUTGOING; - - const Account* a = call->account(); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CALLID ).arg(call->historyId() ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_START ).arg(call->startTimeStamp() ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::TIMESTAMP_STOP ).arg(call->stopTimeStamp() ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::ACCOUNT_ID ).arg(a?QString(a->id()):"" ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DISPLAY_NAME ).arg(call->peerName() ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::PEER_NUMBER ).arg(call->peerContactMethod()->uri().full() ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::DIRECTION ).arg(direction ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::MISSED ).arg(call->isMissed() ); - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_USED ).arg(false );//TODO - - //TODO handle more than one recording - if (call->hasRecording(media::Media::Type::AUDIO,media::Media::Direction::IN)) { - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::RECORDING_PATH ).arg(((media::AVRecording*)call->recordings(media::Media::Type::AUDIO,media::Media::Direction::IN)[0])->path().path()); - } - - if (call->peerContactMethod()->contact()) { - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CONTACT_UID ).arg( - QString(call->peerContactMethod()->contact()->uid()) - ); - } - if (call->certificate()) - stream << QString("%1=%2\n").arg(Call::HistoryMapFields::CERT_PATH).arg(call->certificate()->path()); - stream << "\n"; - stream.flush(); -} - -bool LocalHistoryEditor::regenFile(const Call* toIgnore) -{ - QDir dir(QString('/')); - dir.mkpath(lrc::Database::getPath() + QLatin1Char('/') + QString()); - - QFile file(lrc::Database::getPath() + QLatin1Char('/') +"history.ini"); - if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) { - QTextStream stream(&file); - for (const Call* c : CategorizedHistoryModel::instance().getHistoryCalls()) { - if (c != toIgnore) - saveCall(stream, c); - } - file.close(); - return true; - } - return false; -} - -bool LocalHistoryEditor::save(const Call* call) -{ - if (call->collection()->editor<Call>() != this) - return addNew(const_cast<Call*>(call)); - - return regenFile(nullptr); -} - -bool LocalHistoryEditor::remove(const Call* item) -{ - if (regenFile(item)) { - mediator()->removeItem(item); - return true; - } - return false; -} - -bool LocalHistoryEditor::edit( Call* item) -{ - Q_UNUSED(item) - return false; -} - -bool LocalHistoryEditor::addNew( Call* call) -{ - QDir dir(QString('/')); - dir.mkpath(lrc::Database::getPath() + QLatin1Char('/') + QString()); - - if ((call->collection() && call->collection()->editor<Call>() == this) || call->historyId().isEmpty()) return false; - //TODO support \r and \n\r end of line - QFile file(lrc::Database::getPath() + QLatin1Char('/')+"history.ini"); - - if ( file.open(QIODevice::Append | QIODevice::Text) ) { - QTextStream streamFileOut(&file); - saveCall(streamFileOut, call); - file.close(); - - const_cast<Call*>(call)->setCollection(m_pCollection); - addExisting(call); - return true; - } - else - qWarning() << "Unable to save history"; - return false; -} - -bool LocalHistoryEditor::addExisting(const Call* item) -{ - m_lItems << const_cast<Call*>(item); - mediator()->addItem(item); - return true; -} - -QVector<Call*> LocalHistoryEditor::items() const -{ - return m_lItems; -} - -QString LocalHistoryCollection::name () const -{ - return QObject::tr("Local history"); -} - -QString LocalHistoryCollection::category () const -{ - return QObject::tr("History"); -} - -QVariant LocalHistoryCollection::icon() const -{ - return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::HISTORY); -} - -bool LocalHistoryCollection::isEnabled() const -{ - return true; -} - -bool LocalHistoryCollection::load() -{ - if (!CategorizedHistoryModel::instance().isHistoryEnabled()) - return false; - - QFile file(lrc::Database::getPath() + QLatin1Char('/') +"history.ini"); - if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) { - QMap<QString,QString> hc; - QStringList lines; - - while (!file.atEnd()) - lines << file.readLine().trimmed(); - file.close(); - - const bool isLimited = CategorizedHistoryModel::instance().isHistoryLimited(); - const long long dayLimit = CategorizedHistoryModel::instance().historyLimit() * 24 * 3600; - - time_t now = time(0); // get time now - - for (const QString& line : lines) { - //The item is complete - if ((line.isEmpty() || !line.size()) && hc.size()) { - Call* pastCall = Call::buildHistoryCall(hc); - - if (!isLimited || ( (now - pastCall->startTimeStamp()) < dayLimit) ) { - pastCall->setCollection(this); - editor<Call>()->addExisting(pastCall); - } - - hc.clear(); - } - // Add to the current set - else { - const int idx = line.indexOf("="); - if (idx >= 0) - hc[line.left(idx)] = line.right(line.size()-idx-1); - } - } - return true; - } - else - qWarning() << "History doesn't exist or is not readable"; - return false; -} - -bool LocalHistoryCollection::reload() -{ - return false; -} - -FlagPack<CollectionInterface::SupportedFeatures> LocalHistoryCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::CLEAR | - CollectionInterface::SupportedFeatures::REMOVE | - CollectionInterface::SupportedFeatures::MANAGEABLE | - CollectionInterface::SupportedFeatures::ADD ; -} - -bool LocalHistoryCollection::clear() -{ - QFile::remove(lrc::Database::getPath() + QLatin1Char('/') +"history.ini"); - return true; -} - -QByteArray LocalHistoryCollection::id() const -{ - return "mhb"; -} diff --git a/src/localprofilecollection.cpp b/src/localprofilecollection.cpp deleted file mode 100644 index b84634d2faebbc63b618340cc8e5224e8d4acb95..0000000000000000000000000000000000000000 --- a/src/localprofilecollection.cpp +++ /dev/null @@ -1,228 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2016-2019 Savoir-faire Linux Inc. * - * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "localprofilecollection.h" - -//Qt -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QHash> -#include <QtCore/QStandardPaths> -#include <QtCore/QUrl> -#include <QtCore/QVector> -#include <QtCore/QDateTime> - -//Ring -#include "database.h" -#include "profile.h" -#include "private/vcardutils.h" -#include "account.h" -#include "accountmodel.h" -#include "person.h" -#include "profilemodel.h" - -class LocalProfileEditor final : public CollectionEditor<Profile> -{ -public: - LocalProfileEditor(CollectionMediator<Profile>* m, LocalProfileCollection* parent); - virtual bool save ( const Profile* item ) override; - virtual bool remove ( const Profile* item ) override; - virtual bool edit ( Profile* item ) override; - virtual bool addNew ( Profile* item ) override; - virtual bool addExisting( const Profile* item ) override; - -private: - virtual QVector<Profile*> items() const override; - - //Helpers - QString path(const Profile* p) const; - - //Attributes - QVector<Profile*> m_lItems; - LocalProfileCollection* m_pCollection; -}; - -LocalProfileEditor::LocalProfileEditor(CollectionMediator<Profile>* m, LocalProfileCollection* parent) : -CollectionEditor<Profile>(m),m_pCollection(parent) -{ - -} - -LocalProfileCollection::LocalProfileCollection(CollectionMediator<Profile>* mediator) : -CollectionInterface(new LocalProfileEditor(mediator,this)) -{ - -} - -LocalProfileCollection::~LocalProfileCollection() -{ - -} - -bool LocalProfileEditor::save(const Profile* pro) -{ - const auto& filename = path(pro); - const auto& result = pro->person()->toVCard(pro->accounts().toList()); - - qDebug() << "Saving profile in:" << filename; - QFile file {filename}; - - if (Q_UNLIKELY(!file.open(QIODevice::WriteOnly))) { - qWarning() << "Can't write to" << filename; - return false; - } - - file.write(result); - file.close(); - - // we need to bind the legacy lrc to the new one. We doing that by using profileUpdated - emit ProfileModel::instance().profileUpdated(pro); - - return true; -} - -bool LocalProfileEditor::remove(const Profile* item) -{ - if (QFile::remove(path(item))) { - mediator()->removeItem(item); - return true; - } - - return false; -} - -bool LocalProfileEditor::edit( Profile* item) -{ - Q_UNUSED(item) - return false; -} - -bool LocalProfileEditor::addNew(Profile* pro) -{ - pro->person()->ensureUid(); - qDebug() << "Creating new profile" << pro->person()->uid(); - m_lItems << pro; - pro->setCollection(m_pCollection); - mediator()->addItem(pro); - save(pro); - return true; -} - -bool LocalProfileEditor::addExisting(const Profile* item) -{ - m_lItems << const_cast<Profile*>(item); - mediator()->addItem(item); - return true; -} - -QVector<Profile*> LocalProfileEditor::items() const -{ - return m_lItems; -} - -QString LocalProfileEditor::path(const Profile* p) const -{ - const QDir profilesDir = (lrc::Database::getPath()) + "/profiles/"; - profilesDir.mkpath(profilesDir.path()); - return QString("%1/%2.vcf") - .arg(profilesDir.absolutePath()) - .arg(QString(p->person()->uid())); -} - -QString LocalProfileCollection::name () const -{ - return QObject::tr("Local profiles"); -} - -QString LocalProfileCollection::category () const -{ - return QObject::tr("Profile Collection"); -} - -QVariant LocalProfileCollection::icon() const -{ - return QVariant(); -} - -bool LocalProfileCollection::isEnabled() const -{ - return true; -} - -bool LocalProfileCollection::load() -{ - const QDir profilesDir = (lrc::Database::getPath()) + "/profiles/"; - qDebug() << "Loading vcf from:" << profilesDir; - - const QStringList entries = profilesDir.entryList({QStringLiteral("*.vcf")}, QDir::Files); - bool hasProfile = false; - - foreach (const QString& item , entries) { - hasProfile = true; - auto personProfile = new Person(nullptr); - QList<Account*> accs; - VCardUtils::mapToPerson(personProfile,QUrl(profilesDir.path()+'/'+item),&accs); - auto profile = new Profile(this, personProfile); - profile->setAccounts(accs.toVector()); - editor<Profile>()->addExisting(profile); - } - - if (!hasProfile) { - //Ring needs at least one global profile - setupDefaultProfile(); - } - return true; -} - -bool LocalProfileCollection::reload() -{ - return true; -} - -FlagPack<CollectionInterface::SupportedFeatures> LocalProfileCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::CLEAR | - CollectionInterface::SupportedFeatures::REMOVE | - CollectionInterface::SupportedFeatures::MANAGEABLE | - CollectionInterface::SupportedFeatures::ADD ; -} - -bool LocalProfileCollection::clear() -{ - QFile::remove((lrc::Database::getPath()) + "/profiles/"); - return true; -} - -QByteArray LocalProfileCollection::id() const -{ - return "lpc"; -} - -void LocalProfileCollection::setupDefaultProfile() -{ - auto profile = new Profile(this, new Person()); - profile->person()->setFormattedName(QObject::tr("Default")); - - for (int i = 0 ; i < AccountModel::instance().size() ; i++) { - profile->addAccount(AccountModel::instance()[i]); - } - - editor<Profile>()->addNew(profile); -} diff --git a/src/localrecordingcollection.cpp b/src/localrecordingcollection.cpp deleted file mode 100644 index 968d9b6280b357fd5c788c6aa17df55051f511d0..0000000000000000000000000000000000000000 --- a/src/localrecordingcollection.cpp +++ /dev/null @@ -1,158 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "localrecordingcollection.h" - -//Qt -#include <QtCore/QUrl> - -#include <globalinstances.h> -#include <interfaces/pixmapmanipulatori.h> -#include <media/recordingmodel.h> -#include <media/recording.h> -#include <media/avrecording.h> - -class LocalRecordingEditor final : public CollectionEditor<media::Recording> -{ -public: - LocalRecordingEditor(CollectionMediator<media::Recording>* m) : CollectionEditor<media::Recording>(m) {} - virtual bool save ( const media::Recording* item ) override; - virtual bool remove ( const media::Recording* item ) override; - virtual bool edit (media::Recording* item ) override; - virtual bool addNew (media::Recording* item ) override; - virtual bool addExisting( const media::Recording* item ) override; - -private: - virtual QVector<media::Recording*> items() const override; - //Attributes - QVector<media::Recording*> m_lNumbers; -}; - -LocalRecordingCollection::LocalRecordingCollection(CollectionMediator<media::Recording>* mediator) : - CollectionInterface(new LocalRecordingEditor(mediator)) -{ - load(); -} - -LocalRecordingCollection::~LocalRecordingCollection() -{ - -} - -LocalRecordingCollection& LocalRecordingCollection::instance() -{ - static auto instance = media::RecordingModel::instance().addCollection<LocalRecordingCollection>(); - return *instance; -} - -bool LocalRecordingEditor::save(const media::Recording* recording) -{ - Q_UNUSED(recording) - return true; -} - -bool LocalRecordingEditor::remove(const media::Recording* item) -{ - Q_UNUSED(item) - //TODO - return false; -} - -bool LocalRecordingEditor::edit(media::Recording* item) -{ - Q_UNUSED(item) - return false; -} - -bool LocalRecordingEditor::addNew(media::Recording* item) -{ - addExisting(item); - return save(item); -} - -bool LocalRecordingEditor::addExisting(const media::Recording* item) -{ - m_lNumbers << const_cast<media::Recording*>(item); - mediator()->addItem(item); - return false; -} - -QVector<media::Recording*> LocalRecordingEditor::items() const -{ - return m_lNumbers; -} - -QString LocalRecordingCollection::name () const -{ - return QObject::tr("Local recordings"); -} - -QString LocalRecordingCollection::category () const -{ - return QObject::tr("Recording"); -} - -QVariant LocalRecordingCollection::icon() const -{ - return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::RECORDING); -} - -bool LocalRecordingCollection::isEnabled() const -{ - return true; -} - -bool LocalRecordingCollection::load() -{ - //This collection is special as it use the history collection - //as its source, there is no loading - return true; -} - -bool LocalRecordingCollection::reload() -{ - return false; -} - -FlagPack<CollectionInterface::SupportedFeatures> LocalRecordingCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::ADD | - CollectionInterface::SupportedFeatures::MANAGEABLE| - CollectionInterface::SupportedFeatures::REMOVE ; -} - -bool LocalRecordingCollection::clear() -{ - return false; -} - -QByteArray LocalRecordingCollection::id() const -{ - return "localrecording"; -} - -media::Recording* LocalRecordingCollection::addFromPath(const QString& path) -{ - media::AVRecording* rec = new media::AVRecording(); - rec->setPath(path); - - editor<media::Recording>()->addExisting(rec); - return rec; -} diff --git a/src/localrecordingcollection.h b/src/localrecordingcollection.h deleted file mode 100644 index ea37dcc045fbe86671ac9d0591e93513790ebe06..0000000000000000000000000000000000000000 --- a/src/localrecordingcollection.h +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <collectioninterface.h> -#include <typedefs.h> -#include <collectioneditor.h> - -namespace media { - class Recording; -} - -class LIB_EXPORT LocalRecordingCollection : public CollectionInterface -{ -public: - explicit LocalRecordingCollection(CollectionMediator<media::Recording>* mediator); - virtual ~LocalRecordingCollection(); - - virtual bool load () override; - virtual bool reload() override; - virtual bool clear () override; - - virtual QString name () const override; - virtual QString category () const override; - virtual QVariant icon () const override; - virtual bool isEnabled() const override; - virtual QByteArray id () const override; - - virtual FlagPack<SupportedFeatures> supportedFeatures() const override; - - //Mutator - media::Recording* addFromPath(const QString& path); - - static LocalRecordingCollection& instance(); - -}; diff --git a/src/localringtonecollection.cpp b/src/localringtonecollection.cpp deleted file mode 100644 index f63e47ed4a44fd959a742608ca597dd766fc3e2f..0000000000000000000000000000000000000000 --- a/src/localringtonecollection.cpp +++ /dev/null @@ -1,279 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "localringtonecollection.h" - -//Qt -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QHash> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonArray> -#include <QtCore/QJsonObject> -#include <QtCore/QCoreApplication> -#include <QtCore/QStandardPaths> -#include <QtCore/QUrl> - -//Ring -#include <collectioneditor.h> -#include "database.h" -#include <ringtonemodel.h> -#include <ringtone.h> -#include <globalinstances.h> -#include <interfaces/pixmapmanipulatori.h> - -namespace Serializable { - class RingtoneNode - { - public: - Ringtone* ringtone; - - void read (const QJsonObject &json); - void write(QJsonObject &json); - }; -} - -class LocalRingtoneEditor final : public CollectionEditor<Ringtone> -{ -public: - LocalRingtoneEditor(CollectionMediator<Ringtone>* m) - : CollectionEditor<Ringtone>(m),m_Tracked(false) {} - virtual bool save ( const Ringtone* item ) override; - virtual bool remove ( const Ringtone* item ) override; - virtual bool addNew ( Ringtone* item ) override; - virtual bool addExisting( const Ringtone* item ) override; - - //Attributes - QVector<Ringtone*> m_lNumbers; - QList<Serializable::RingtoneNode> m_Nodes; - bool m_Tracked; - -private: - virtual QVector<Ringtone*> items() const override; -}; - -class LocalRingtoneCollectionPrivate -{ -public: - - //Attributes - constexpr static const char FILENAME[] = "ringtone.json"; -}; - -constexpr const char LocalRingtoneCollectionPrivate::FILENAME[]; - -LocalRingtoneCollection::LocalRingtoneCollection(CollectionMediator<Ringtone>* mediator) : - CollectionInterface(new LocalRingtoneEditor(mediator)) -{ - load(); -} - - -LocalRingtoneCollection::~LocalRingtoneCollection() -{ - delete d_ptr; -} - -bool LocalRingtoneCollection::load() -{ - QFile file(lrc::Database::getPath() - + QLatin1Char('/') + LocalRingtoneCollectionPrivate::FILENAME); - LocalRingtoneEditor* e = static_cast<LocalRingtoneEditor*>(editor<Ringtone>()); - - if ( file.open(QIODevice::ReadOnly | QIODevice::Text) ) { - const QByteArray content = file.readAll(); - QJsonDocument loadDoc = QJsonDocument::fromJson(content); - QJsonArray a = loadDoc.array(); - //QHash<QString,bool> uniqueRingtone; //TODO make sure there is no duplicates - - //TODO implement custom ringtone path, that's the code to load/save them - for (int i = 0; i < a.size(); ++i) { - QJsonObject o = a[i].toObject(); - Serializable::RingtoneNode n; - n.read(o); - - n.ringtone->setCollection(this); - e->addExisting(n.ringtone); - - e->m_Nodes << n; - } - } - else - qWarning() << "Ringtones doesn't exist or is not readable"; - -//TODO remove that and do a proper collection for each platforms -#ifdef Q_OS_LINUX - QDir ringtonesDir(QFileInfo(QCoreApplication::applicationFilePath()).path()+"/../share/ring/ringtones/"); -#elif defined(Q_OS_WIN) - QDir ringtonesDir(QFileInfo(QCoreApplication::applicationFilePath()).path()+"/ringtones/"); -#elif defined(Q_OS_OSX) - QDir ringtonesDir(QCoreApplication::applicationDirPath()); - ringtonesDir.cdUp(); - ringtonesDir.cd("Resources/ringtones/"); -#endif - - if(!ringtonesDir.exists()) - return true; - const QStringList entries = ringtonesDir.entryList({"*.wav", "*.ul", "*.au", "*.flac"}, QDir::Files); - for (const QString& item : entries) { - QFileInfo fileinfo(ringtonesDir.absolutePath()+"/"+item); - Ringtone* info = new Ringtone(); - info->setPath(fileinfo.absoluteFilePath()); - info->setName(item); - e->addExisting(info); - } - - return true; -} - -bool LocalRingtoneEditor::save(const Ringtone* ringtone) -{ - Q_UNUSED(ringtone) - - QFile file(lrc::Database::getPath() - + QLatin1Char('/') + LocalRingtoneCollectionPrivate::FILENAME); - if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) { - - QJsonArray a; - for (Serializable::RingtoneNode& g : m_Nodes) { - QJsonObject o; - g.write(o); - a.append(o); - } - - QJsonDocument doc(a); - - QTextStream streamFileOut(&file); - streamFileOut << doc.toJson(); - streamFileOut.flush(); - file.close(); - - return true; - } - else - qWarning() << "Unable to save ringtones"; - - return false; -} - -bool LocalRingtoneEditor::remove(const Ringtone* item) -{ - Q_UNUSED(item) - - if (m_lNumbers.indexOf(const_cast<Ringtone*>(item)) != -1) { - m_lNumbers.removeAt(m_lNumbers.indexOf(const_cast<Ringtone*>(item))); - mediator()->removeItem(item); - - for (int i =0;i<m_Nodes.size();i++) { - if (m_Nodes[i].ringtone == item) { - m_Nodes.removeAt(i); - break; - } - } - - return save(nullptr); - } - return false; -} - -bool LocalRingtoneEditor::addNew( Ringtone* ringtone) -{ - Serializable::RingtoneNode n; - - n.ringtone = ringtone; - m_Nodes << n; - - if (!save(ringtone)) - qWarning() << "Unable to save ringtones"; - - addExisting(ringtone); - return save(ringtone); -} - -bool LocalRingtoneEditor::addExisting(const Ringtone* item) -{ - m_lNumbers << const_cast<Ringtone*>(item); - mediator()->addItem(item); - return false; -} - -QVector<Ringtone*> LocalRingtoneEditor::items() const -{ - return m_lNumbers; -} - -QString LocalRingtoneCollection::name () const -{ - return QObject::tr("Local ringtones"); -} - -QString LocalRingtoneCollection::category () const -{ - return QObject::tr("Ringtone"); -} - -QVariant LocalRingtoneCollection::icon() const -{ - return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::MACRO); -} - -bool LocalRingtoneCollection::isEnabled() const -{ - return true; -} - -bool LocalRingtoneCollection::reload() -{ - return false; -} - -FlagPack<CollectionInterface::SupportedFeatures> LocalRingtoneCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::CLEAR | - CollectionInterface::SupportedFeatures::ADD | - CollectionInterface::SupportedFeatures::MANAGEABLE| - CollectionInterface::SupportedFeatures::REMOVE ; -} - -bool LocalRingtoneCollection::clear() -{ - return QFile::remove(lrc::Database::getPath() - + QLatin1Char('/') + LocalRingtoneCollectionPrivate::FILENAME); -} - -QByteArray LocalRingtoneCollection::id() const -{ - return "localringtone"; -} - -void Serializable::RingtoneNode::read(const QJsonObject &json) -{ - ringtone = new Ringtone(); - ringtone->setPath(json["path"].toString()); - ringtone->setName(json["name"].toString()); -} - -void Serializable::RingtoneNode::write(QJsonObject& json) -{ - json["path"] = ringtone->path(); - json["name"] = ringtone->name(); -} - -#include <localringtonecollection.moc> diff --git a/src/localtextrecordingcollection.cpp b/src/localtextrecordingcollection.cpp deleted file mode 100644 index 76da18931f085662b2fd82936b2272b15e256bf7..0000000000000000000000000000000000000000 --- a/src/localtextrecordingcollection.cpp +++ /dev/null @@ -1,341 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "localtextrecordingcollection.h" - -//Qt -#include <QtCore/QDir> -#include <QtCore/QFile> -#include <QtCore/QStandardPaths> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonObject> - -//Ring -#include "database.h" -#include <globalinstances.h> -#include <interfaces/pixmapmanipulatori.h> -#include <media/recordingmodel.h> -#include <media/recording.h> -#include <media/textrecording.h> -#include <private/textrecording_p.h> -#include <private/contactmethod_p.h> -#include <media/media.h> - -/* - * This collection store and load the instant messaging conversations. Lets call - * them "imc" for this section. An imc is a graph of one or more groups. Groups - * are concatenated into a json file with the ContactMethod sha1 as filename. - * Each group has a next group. If the next group is null, then the next one in - * file will be used. If it isn't then another json file can be linked. Once the - * second file has no next group, the next group from the first file is used. - * - * If more than 1 peer is part of the conversation, then their hash are - * concatenated then hashed in sha1 again. - */ - -class LocalTextRecordingEditor final : public CollectionEditor<media::Recording> -{ -public: - LocalTextRecordingEditor(CollectionMediator<media::Recording>* m) : CollectionEditor<media::Recording>(m) {} - virtual bool save ( const media::Recording* item ) override; - virtual bool remove ( const media::Recording* item ) override; - virtual bool edit ( media::Recording* item ) override; - virtual bool addNew ( media::Recording* item ) override; - virtual bool addExisting( const media::Recording* item ) override; - QString fetch(const QByteArray& sha1); - - void clearAll(); - -private: - virtual QVector<media::Recording*> items() const override; - //Attributes - QVector<media::Recording*> m_lNumbers; -}; - -LocalTextRecordingCollection::LocalTextRecordingCollection(CollectionMediator<media::Recording>* mediator) : - CollectionInterface(new LocalTextRecordingEditor(mediator)) -{ - load(); -} - -LocalTextRecordingCollection::~LocalTextRecordingCollection() -{ - -} - -LocalTextRecordingCollection& LocalTextRecordingCollection::instance() -{ - static auto instance = media::RecordingModel::instance().addCollection<LocalTextRecordingCollection>(); - return *instance; -} - -bool LocalTextRecordingEditor::save(const media::Recording* recording) -{ - Q_UNUSED(recording) - QHash<QByteArray,QByteArray> ret = static_cast<const media::TextRecording*>(recording)->d_ptr->toJsons(); - - QDir dir(lrc::Database::getPath()); - - //Make sure the directory exist - dir.mkdir("text/"); - - //Save each file - for (QHash<QByteArray,QByteArray>::const_iterator i = ret.begin(); i != ret.end(); ++i) { - QFile file(QString("%1/text/%2.json").arg(dir.path()).arg(QString(i.key()))); - - if ( file.open(QIODevice::WriteOnly | QIODevice::Text) ) { - QTextStream streamFileOut(&file); - streamFileOut.setCodec("UTF-8"); - streamFileOut << i.value(); - streamFileOut.flush(); - file.close(); - } - } - - return true; -} - -void LocalTextRecordingEditor::clearAll() -{ - for (media::Recording *recording : items()) { - auto textRecording = qobject_cast<media::TextRecording*>(recording); - textRecording->d_ptr->clear(); - save(recording); - } -} - -bool LocalTextRecordingEditor::remove(const media::Recording* item) -{ - Q_UNUSED(item) - //TODO - return false; -} - -bool LocalTextRecordingEditor::edit( media::Recording* item) -{ - Q_UNUSED(item) - return false; -} - -bool LocalTextRecordingEditor::addNew( media::Recording* item) -{ - Q_UNUSED(item) - addExisting(item); - return save(item); -} - -bool LocalTextRecordingEditor::addExisting(const media::Recording* item) -{ - m_lNumbers << const_cast<media::Recording*>(item); - mediator()->addItem(item); - return false; -} - -QString LocalTextRecordingEditor::fetch(const QByteArray& sha1) -{ - QFile file(lrc::Database::getPath() + "/text/" + sha1 + ".json"); - - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return QByteArray(); - } - - return QString::fromUtf8(file.readAll()); -} - -QVector<media::Recording*> LocalTextRecordingEditor::items() const -{ - return m_lNumbers; -} - -QString LocalTextRecordingCollection::name () const -{ - return QObject::tr("Local text recordings"); -} - -QString LocalTextRecordingCollection::category () const -{ - return QObject::tr("Recording"); -} - -QVariant LocalTextRecordingCollection::icon() const -{ - return GlobalInstances::pixmapManipulator().collectionIcon(this,Interfaces::PixmapManipulatorI::CollectionIconHint::RECORDING); -} - -bool LocalTextRecordingCollection::isEnabled() const -{ - return true; -} - -bool LocalTextRecordingCollection::load() -{ - // load all text recordings so we can recover CMs that are not in the call history - QDir dir(lrc::Database::getPath() + "/text/"); - if (dir.exists()) { - // get .json files, sorted by time, latest first - QStringList filters; - filters << "*.json"; - auto list = dir.entryInfoList(filters, QDir::Files | QDir::NoSymLinks | QDir::Readable, QDir::Time); - - for (int i = 0; i < list.size(); ++i) { - QFileInfo fileInfo = list.at(i); - - QString content; - QFile file(fileInfo.absoluteFilePath()); - if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { - content = QString::fromUtf8(file.readAll()); - } else { - qWarning() << "Could not open text recording json file"; - } - - if (!content.isEmpty()) { - QJsonParseError err; - QJsonDocument loadDoc = QJsonDocument::fromJson(content.toUtf8(), &err); - - if (err.error == QJsonParseError::ParseError::NoError) { - media::TextRecording* r = media::TextRecording::fromJson({loadDoc.object()}, nullptr, this); - - editor<media::Recording>()->addExisting(r); - - // get CMs from recording - for (ContactMethod *cm : r->peers()) { - // since we load the recordings in order from newest to oldest, if there is - // more than one found associated with a CM, we take the newest one - if (!cm->d_ptr->m_pTextRecording) { - cm->d_ptr->setTextRecording(r); - } else { - qWarning() << "CM already has text recording" << cm; - } - } - } else { - qWarning() << "Error Decoding Text Message History Json" << err.errorString(); - } - } else { - qWarning() << "Text recording file is empty"; - } - } - } - - // always return true, even if noting was loaded, since the collection can still be used to - // save files - return true; -} - -bool LocalTextRecordingCollection::reload() -{ - return false; -} - -FlagPack<CollectionInterface::SupportedFeatures> LocalTextRecordingCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::ADD | - CollectionInterface::SupportedFeatures::SAVE | - CollectionInterface::SupportedFeatures::MANAGEABLE| - CollectionInterface::SupportedFeatures::SAVE_ALL | - CollectionInterface::SupportedFeatures::LISTABLE | - CollectionInterface::SupportedFeatures::REMOVE | - CollectionInterface::SupportedFeatures::CLEAR ; -} - -bool LocalTextRecordingCollection::clear() -{ - static_cast<LocalTextRecordingEditor *>(editor<media::Recording>())->clearAll(); - - QDir dir(lrc::Database::getPath() + "/text"); - - // TODO: the file deletion should be done on each individual file to be able to catch errors - // and to prevent us deleting files which are not the recordings - return dir.removeRecursively(); -} - -QByteArray LocalTextRecordingCollection::id() const -{ - return "localtextrecording"; -} - -bool LocalTextRecordingCollection::listId(std::function<void(const QList<Element>)> callback) const -{ - QList<Element> list; - - QDir dir(lrc::Database::getPath() + "/text/"); - - if (!dir.exists()) - return false; - - for (const QString& str : dir.entryList({"*.json"}) ) { - list << str.toLatin1(); - } - - callback(list); - return true; -} - -QList<CollectionInterface::Element> LocalTextRecordingCollection::listId() const -{ - return {}; -} - -bool LocalTextRecordingCollection::fetch(const Element& e) -{ - Q_UNUSED(e); - return false; -} - -bool LocalTextRecordingCollection::fetch( const QList<CollectionInterface::Element>& elements) -{ - Q_UNUSED(elements) - return false; -} - -media::TextRecording* LocalTextRecordingCollection::fetchFor(const ContactMethod* cm) -{ - const QByteArray& sha1 = cm->sha1(); - const QString content = static_cast<LocalTextRecordingEditor*>(editor<media::Recording>())->fetch(sha1); - - if (content.isEmpty()) - return nullptr; - - QJsonParseError err; - QJsonDocument loadDoc = QJsonDocument::fromJson(content.toUtf8(), &err); - - if (err.error != QJsonParseError::ParseError::NoError) { - qWarning() << "Error Decoding Text Message History Json" << err.errorString(); - return nullptr; - } - - media::TextRecording* r = media::TextRecording::fromJson({loadDoc.object()}, cm, this); - - editor<media::Recording>()->addExisting(r); - - return r; -} - -media::TextRecording* LocalTextRecordingCollection::createFor(const ContactMethod* cm) -{ - media::TextRecording* r = fetchFor(cm); - - if (!r) { - r = new media::TextRecording(); - r->setCollection(this); - cm->d_ptr->setTextRecording(r); - } - - return r; -} diff --git a/src/localtextrecordingcollection.h b/src/localtextrecordingcollection.h deleted file mode 100644 index 3f85c67ff343f358c3fc61ca80ca83b5c102f197..0000000000000000000000000000000000000000 --- a/src/localtextrecordingcollection.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <collectioninterface.h> -#include <collectioneditor.h> - -#include <typedefs.h> - -namespace media { - class Recording; - class TextRecording; -} - -class LIB_EXPORT LocalTextRecordingCollection : public CollectionInterface -{ -public: - explicit LocalTextRecordingCollection(CollectionMediator<media::Recording>* mediator); - virtual ~LocalTextRecordingCollection(); - - virtual bool load () override; - virtual bool reload() override; - virtual bool clear () override; - - virtual QString name () const override; - virtual QString category () const override; - virtual QVariant icon () const override; - virtual bool isEnabled() const override; - virtual QByteArray id () const override; - virtual bool fetch(const Element& e) override; - virtual bool fetch(const QList<CollectionInterface::Element>& elements) override; - virtual bool listId(std::function<void(const QList<Element>)> callback) const override; - virtual QList<Element> listId() const override; - - media::TextRecording* fetchFor (const ContactMethod* cm); - media::TextRecording* createFor(const ContactMethod* cm); - - virtual FlagPack<SupportedFeatures> supportedFeatures() const override; - - static LocalTextRecordingCollection& instance(); - -}; diff --git a/src/lrc.cpp b/src/lrc.cpp index ad0b92368446f04fe93d836522c9041ca31e674a..fedcb972be7fec0af373e8586c33fa58eff3f0b6 100644 --- a/src/lrc.cpp +++ b/src/lrc.cpp @@ -34,6 +34,7 @@ #include "dbus/callmanager.h" #include "dbus/configurationmanager.h" #include "dbus/instancemanager.h" +#include "dbus/configurationmanager.h" namespace lrc { diff --git a/src/macro.cpp b/src/macro.cpp deleted file mode 100644 index 46292783926db98a5207516acc008404d2e6894b..0000000000000000000000000000000000000000 --- a/src/macro.cpp +++ /dev/null @@ -1,173 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "macro.h" - -//Qt -#include <QtCore/QTimer> - -//Ring -#include "audio/outputdevicemodel.h" -#include "private/macromodel_p.h" - - -MacroPrivate::MacroPrivate() : m_Position(0),m_Delay(0),m_pCat(nullptr),m_pPointer(nullptr), -m_pModel(nullptr) -{ - -} - -Macro::Macro(QObject* parent) : ItemBase(parent), d_ptr(new MacroPrivate()) -{ -} - -Macro::Macro(const Macro* macro) : ItemBase(nullptr), d_ptr(new MacroPrivate()) -{ - d_ptr->m_Position = macro->d_ptr->m_Position ; - d_ptr->m_Name = macro->d_ptr->m_Name ; - d_ptr->m_Description = macro->d_ptr->m_Description; - d_ptr->m_Sequence = macro->d_ptr->m_Sequence ; - d_ptr->m_Escaped = macro->d_ptr->m_Escaped ; - d_ptr->m_Id = macro->d_ptr->m_Id ; - d_ptr->m_Delay = macro->d_ptr->m_Delay ; - d_ptr->m_Category = macro->d_ptr->m_Category ; - d_ptr->m_Action = macro->d_ptr->m_Action ; - d_ptr->m_pCat = macro->d_ptr->m_pCat ; - d_ptr->m_pModel = macro->d_ptr->m_pModel ; - d_ptr->m_pPointer = macro->d_ptr->m_pPointer ; -} - -Macro::~Macro() -{ - delete d_ptr; -} - -void Macro::execute() { - d_ptr->m_Escaped = d_ptr->m_Sequence; - while (d_ptr->m_Escaped.indexOf("\\n") != -1) { - d_ptr->m_Escaped = d_ptr->m_Escaped.replace("\\n","\n"); - } - d_ptr->nextStep(); -} - -void MacroPrivate::nextStep() -{ - if (m_Position < m_Escaped.size()) { - if (!MacroModel::instance().d_ptr->m_lListeners.size()) - Audio::OutputDeviceModel::playDTMF(QString(m_Escaped[m_Position])); - else { - foreach(MacroModel::MacroListener* l, MacroModel::instance().d_ptr->m_lListeners) { - l->addDTMF(QString(m_Escaped[m_Position])); - } - } - m_Position++; - QTimer::singleShot(m_Delay?m_Delay:100,this,SLOT(nextStep())); - } - else { - m_Position = 0; - } -} - -QModelIndex Macro::index() -{ - QModelIndex parent = d_ptr->m_pModel->index(d_ptr->m_pModel->d_ptr->m_lCategories.indexOf(d_ptr->m_pCat),0,QModelIndex()); - return d_ptr->m_pModel->index(d_ptr->m_pCat->m_lContent.indexOf(this),0,parent); -} - -void Macro::setName(const QString &value) -{ - d_ptr->m_Name = value; - emit changed(this); - //d_ptr->m_Action->setText(m_Name); -} - -void Macro::setDescription(const QString &value) -{ - d_ptr->m_Description = value; - emit changed(this); -} -void Macro::setSequence(const QString &value) -{ - d_ptr->m_Sequence = value; - emit changed(this); -} - -void Macro::setEscaped(const QString &value) -{ - d_ptr->m_Escaped = value; - emit changed(this); -} - -void Macro::setId(const QString &value) -{ - d_ptr->m_Id = value; - emit changed(this); -} - -void Macro::setDelay(int value) -{ - d_ptr->m_Delay = value; - emit changed(this); -} - -void Macro::setCategory(const QString &value) -{ - d_ptr->m_Category = value; - emit changed(this); -} - -QString Macro::name() const -{ - return d_ptr->m_Name; -} - -QString Macro::description() const -{ - return d_ptr->m_Description; -} - -QString Macro::sequence() const -{ - return d_ptr->m_Sequence; -} - -QString Macro::escaped() const -{ - return d_ptr->m_Escaped; -} - -QString Macro::id() const -{ - return d_ptr->m_Id; -} - -int Macro::delay() const -{ - return d_ptr->m_Delay; -} - -QString Macro::category() const -{ - return d_ptr->m_Category; -} - -QVariant Macro::action() const -{ - return d_ptr->m_Action; -} - -#include <macro.moc> diff --git a/src/macro.h b/src/macro.h deleted file mode 100644 index 9b2a8f2a59feefca8f0b9846e9c0612615c31288..0000000000000000000000000000000000000000 --- a/src/macro.h +++ /dev/null @@ -1,79 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QObject> -#include <QtCore/QDateTime> -#include <QtCore/QModelIndex> - -//Ring -class MacroModel; -#include "typedefs.h" -#include "itembase.h" - -class MacroPrivate; - -class LIB_EXPORT Macro : public ItemBase -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - - friend class MacroModel ; //Use factory method - friend class MacroModelPrivate; //Use factory method - -public: - explicit Macro(const Macro* macro); - virtual ~Macro(); - - //Getters - QString name () const; - QString description () const; - QString sequence () const; - QString escaped () const; - QString id () const; - int delay () const; - QString category () const; - QVariant action () const; - - QModelIndex index(); - - //Setters - void setName (const QString &value); - void setDescription (const QString &value); - void setSequence (const QString &value); - void setEscaped (const QString &value); - void setId (const QString &value); - void setDelay (int value); - void setCategory (const QString &value); - -private: - explicit Macro(QObject* parent = nullptr); - - MacroPrivate* d_ptr; - Q_DECLARE_PRIVATE(Macro) - -public Q_SLOTS: - void execute(); - -Q_SIGNALS: - void changed(Macro*); -}; - diff --git a/src/macromodel.cpp b/src/macromodel.cpp deleted file mode 100644 index 231dd7b7fd5840605a97700aac8db58d501d1d50..0000000000000000000000000000000000000000 --- a/src/macromodel.cpp +++ /dev/null @@ -1,318 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "macromodel.h" - -//System -#include <time.h> - -//Qt -#include <QtCore/QTimer> -#include <QtCore/QFile> -#include <QtCore/QStandardPaths> - -//Ring -#include "macro.h" -#include "private/macromodel_p.h" -#include "globalinstances.h" -#include "interfaces/shortcutcreatori.h" - -MacroModelPrivate::MacroModelPrivate(MacroModel* parent) : q_ptr(parent), -m_pCurrentMacro(nullptr),m_pCurrentMacroMemento(nullptr) -{ - -} - -MacroModel::MacroModel(QObject* parent) : QAbstractItemModel(parent), d_ptr(new MacroModelPrivate(this)), CollectionManagerInterface<Macro>(this) -{ - -} - -MacroModel::~MacroModel() -{ - delete d_ptr; -} - -///Singleton -MacroModel& MacroModel::instance() -{ - static auto instance = new MacroModel(0); - return *instance; -} - -void MacroModel::addListener(MacroListener* interface) -{ - instance().d_ptr->m_lListeners << interface; -} - -MacroModelPrivate::MacroCategory* MacroModelPrivate::createCategory(const QString& name) -{ - MacroCategory* cat = new MacroCategory; - cat->m_Name = name; - cat->m_pPointer = new IndexPointer(IndexType::CategoryIndex,cat); - m_lCategories << cat; - emit q_ptr->dataChanged(q_ptr->index((m_lCategories.size()-2 > 0)? m_lCategories.size()-2:0,0,QModelIndex()), - q_ptr->index((m_lCategories.size()-1>0 )? m_lCategories.size()-1:0,0,QModelIndex())); - emit q_ptr->layoutChanged(); - return cat; -} - -void MacroModelPrivate::updateTreeModel(Macro* newMacro) -{ - QString catName = newMacro->d_ptr->m_Category.isEmpty()?tr("Other"):newMacro->d_ptr->m_Category; - foreach (MacroCategory* cat, m_lCategories) { - if (cat->m_Name == catName) { - cat->m_lContent << newMacro; - newMacro->d_ptr->m_pCat = cat; - newMacro->d_ptr->m_Category = cat->m_Name; - newMacro->d_ptr->m_pPointer = new IndexPointer(IndexType::MacroIndex,newMacro); - return; - } - } - MacroCategory* cat = createCategory(catName); - cat->m_lContent << newMacro; - newMacro->d_ptr->m_pCat = cat; - newMacro->d_ptr->m_pPointer = new IndexPointer(IndexType::MacroIndex,newMacro); -} - -//Remove the selected macro -bool MacroModel::removeMacro(const QModelIndex& idx) -{ - MacroModelPrivate::IndexPointer* modelItem = (MacroModelPrivate::IndexPointer*)idx.internalPointer(); - if (modelItem && modelItem->type == MacroModelPrivate::IndexType::MacroIndex) { - Macro* macro = static_cast<Macro*>(modelItem->data); - macro->remove(); - MacroModelPrivate::MacroCategory* cat = macro->d_ptr->m_pCat; - cat->m_lContent.removeAll(macro); - emit layoutChanged(); - } - else - qWarning() << "Cannot remove macro: none is selected"; - return true; -} - -void MacroModel::setCurrent(const QModelIndex& current, const QModelIndex& previous) -{ - Q_UNUSED(previous) - if (!current.isValid()) - return; - MacroModelPrivate::IndexPointer* modelItem = (MacroModelPrivate::IndexPointer*)current.internalPointer(); - if (modelItem && modelItem->type == MacroModelPrivate::IndexType::MacroIndex) { - Macro* macro = static_cast<Macro*>(modelItem->data); - d_ptr->m_pCurrentMacro = macro; - emit selectMacro(d_ptr->m_pCurrentMacro); - } -} - -void MacroModel::save() -{ - foreach (MacroModelPrivate::MacroCategory* cat, d_ptr->m_lCategories) { - foreach(Macro* macro,cat->m_lContent) { - macro->save(); - return; - } - } -} - -bool MacroModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QVariant MacroModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - if (!index.parent().isValid() && (role == Qt::DisplayRole || role == Qt::EditRole)) { - return QVariant(d_ptr->m_lCategories[index.row()]->m_Name); - } - else if (index.parent().isValid() && (role == Qt::DisplayRole || role == Qt::EditRole)) { - return QVariant(d_ptr->m_lCategories[index.parent().row()]->m_lContent[index.row()]->d_ptr->m_Name); - } - return QVariant(); -} - -QVariant MacroModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(section) - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return QVariant(tr("Macros")); - return QVariant(); -} - -int MacroModel::rowCount( const QModelIndex& parent ) const -{ - if (!parent.isValid()) { - return d_ptr->m_lCategories.size(); - } - else if (!parent.parent().isValid() && parent.row() < d_ptr->m_lCategories.size()) { - return d_ptr->m_lCategories[parent.row()]->m_lContent.size(); - } - return 0; -} - -Qt::ItemFlags MacroModel::flags( const QModelIndex& index ) const -{ - if (!index.isValid()) - return 0; - return Qt::ItemIsEnabled | ((index.parent().isValid())?Qt::ItemIsSelectable:Qt::ItemIsEnabled); -} - -int MacroModel::columnCount ( const QModelIndex& parent) const -{ - Q_UNUSED(parent) - return 1; -} - -QModelIndex MacroModel::parent( const QModelIndex& index) const -{ - if (!index.isValid()) - return QModelIndex(); - MacroModelPrivate::IndexPointer* modelItem = (MacroModelPrivate::IndexPointer*)index.internalPointer(); - if (modelItem && modelItem->type == MacroModelPrivate::IndexType::MacroIndex) { - const int idx = d_ptr->m_lCategories.indexOf(static_cast<Macro*>(modelItem->data)->d_ptr->m_pCat); - if (idx != -1) { - return MacroModel::index(idx,0,QModelIndex()); - } - } - return QModelIndex(); -} - -QModelIndex MacroModel::index( int row, int column, const QModelIndex& parent) const -{ - if (column != 0 || parent.parent().isValid()) - return QModelIndex(); - - if ((!parent.isValid()) && d_ptr->m_lCategories.size() > row && row >= 0) { - return createIndex(row,column,d_ptr->m_lCategories[row]->m_pPointer); - } - else if (parent.isValid() && d_ptr->m_lCategories[parent.row()]->m_lContent.size() > row && row >= 0) { - return createIndex(row,column,d_ptr->m_lCategories[parent.row()]->m_lContent[row]->d_ptr->m_pPointer); - } - return QModelIndex(); -} - -void MacroModelPrivate::changed(Macro* macro) -{ - if (macro && macro->d_ptr->m_pCat) { - QModelIndex parent = q_ptr->index(m_lCategories.indexOf(macro->d_ptr->m_pCat),0); - emit q_ptr->dataChanged(q_ptr->index(0,0,parent),q_ptr->index(q_ptr->rowCount(parent),0,parent)); - if (macro->d_ptr->m_pCat->m_Name != macro->d_ptr->m_Category) { - MacroCategory* newIdx = nullptr; - foreach (MacroCategory* cat, m_lCategories) { - if (cat->m_Name == macro->d_ptr->m_Category) { - newIdx = cat; - break; - } - } - if (macro->d_ptr->m_pCat->m_lContent.size() == 1 && !newIdx) { //Rename - int idx = m_lCategories.indexOf(macro->d_ptr->m_pCat); - macro->d_ptr->m_pCat->m_Name = macro->d_ptr->m_Category; - emit q_ptr->dataChanged(q_ptr->index(idx,0),q_ptr->index(idx,0)); - return; - } - else { - macro->d_ptr->m_pCat->m_lContent.removeAll(macro); - if (!macro->d_ptr->m_pCat->m_lContent.size()) { - m_lCategories.removeAll(macro->d_ptr->m_pCat); - delete macro->d_ptr->m_pCat; - emit q_ptr->dataChanged(q_ptr->index(0,0),q_ptr->index(m_lCategories.size()-1,0)); - } - macro->d_ptr->m_pCat = nullptr; - } - - if (newIdx) { - newIdx->m_lContent << macro; - macro->d_ptr->m_pCat = newIdx; - macro->d_ptr->m_Category = newIdx->m_Name; - return; - } - MacroCategory* cat = createCategory(macro->d_ptr->m_Category); - cat->m_lContent << macro; - macro->d_ptr->m_pCat = cat; - macro->d_ptr->m_Category = cat->m_Name; - emit q_ptr->layoutChanged(); - } - } -} - - -//Add a new macro if the current one can be saved -Macro* MacroModel::newMacro(const QString& id) -{ - d_ptr->m_pCurrentMacro = new Macro(this); - - d_ptr->m_pCurrentMacro->d_ptr->m_Name = tr("New"); - d_ptr->m_pCurrentMacro->d_ptr->m_Category = tr("Other"); - d_ptr->m_pCurrentMacro->d_ptr->m_pModel = this; - if (id.isEmpty()) { - time_t curTime; - ::time(&curTime); - d_ptr->m_pCurrentMacro->d_ptr->m_Id = QString::number(curTime); - while (d_ptr->m_hMacros[d_ptr->m_pCurrentMacro->d_ptr->m_Id]) { - d_ptr->m_pCurrentMacro->d_ptr->m_Id += '1'; - } - } - else - d_ptr->m_pCurrentMacro->d_ptr->m_Id += id; - d_ptr->m_hMacros[d_ptr->m_pCurrentMacro->d_ptr->m_Id] = d_ptr->m_pCurrentMacro; - - if (collections().size()) { - collections()[0]->add(d_ptr->m_pCurrentMacro); - } - else { - qWarning() << "No macro collection are enabled"; - } - - d_ptr->updateTreeModel(d_ptr->m_pCurrentMacro); - connect(d_ptr->m_pCurrentMacro,SIGNAL(changed(Macro*)),d_ptr,SLOT(changed(Macro*))); - emit dataChanged(index(0,0),index(d_ptr->m_lCategories.size()-1,0)); - emit layoutChanged (); - emit selectMacro(d_ptr->m_pCurrentMacro); - - d_ptr->m_pCurrentMacro->d_ptr->m_Action = GlobalInstances::shortcutCreator().createAction(d_ptr->m_pCurrentMacro); - emit addAction(d_ptr->m_pCurrentMacro->d_ptr->m_Action); - - return d_ptr->m_pCurrentMacro; -} - -Macro* MacroModel::getCurrentMacro() -{ - return d_ptr->m_pCurrentMacro; -} - - -void MacroModel::collectionAddedCallback(CollectionInterface* item) -{ - Q_UNUSED(item) -} - -bool MacroModel::addItemCallback(const Macro* item) -{ - Q_UNUSED(item) - return true; -} - -bool MacroModel::removeItemCallback(const Macro* item) -{ - Q_UNUSED(item) - return true; -} diff --git a/src/macromodel.h b/src/macromodel.h deleted file mode 100644 index cd6c50ed216c15523b91a297e114042a2236f49d..0000000000000000000000000000000000000000 --- a/src/macromodel.h +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QAbstractItemModel> -#include <QtCore/QHash> - -//Ring -#include "typedefs.h" -#include "collectionmanagerinterface.h" - -//Ring -class Macro; -class MacroModelPrivate; - -///MacroModel: DTMF emulators model -class LIB_EXPORT MacroModel : public QAbstractItemModel, public CollectionManagerInterface<Macro> -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - friend class Macro; - friend class MacroPrivate; - -public: - - /** - * Interface to interpret DTMFs instead of using the daemon directly - * - * This can be useful is a client want to add animations - */ - class MacroListener { - public: - explicit MacroListener() {} - virtual void addDTMF(const QString& sequence) = 0; - virtual ~MacroListener() {} - }; - - static MacroModel& instance(); - static void addListener(MacroListener* interface); - - enum MacroFields { - Name = 100, - Category = 101, - Delay = 102, - Description = 103, - Sequence = 104 - }; - - //Getters - Macro* getCurrentMacro(); //TODO replace with a selection model - - //Model implementation - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - -private: - //Singleton constructor - explicit MacroModel(QObject* parent = nullptr); - virtual ~MacroModel(); - - MacroModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(MacroModel) - - //Collection interface - virtual void collectionAddedCallback(CollectionInterface* backend) override; - virtual bool addItemCallback (const Macro* item ) override; - virtual bool removeItemCallback (const Macro* item ) override; - -public Q_SLOTS: - Macro* newMacro(const QString& id = QString()); - bool removeMacro(const QModelIndex& idx); - void setCurrent(const QModelIndex& current, const QModelIndex& previous); //TODO use a selectionmodel - void save(); - -Q_SIGNALS: - void addAction(const QVariant&); - void selectMacro(Macro* macro); -}; - diff --git a/src/media/audio.cpp b/src/media/audio.cpp deleted file mode 100644 index a8c0cafd9a45afda8be9cc381b7945793069156c..0000000000000000000000000000000000000000 --- a/src/media/audio.cpp +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "audio.h" - -//Dring -#include <media_const.h> -#include "dbus/callmanager.h" - -//Ring -#include <call.h> - -class MediaAudioPrivate -{ -}; - -media::Audio::Audio(Call* parent, const media::Media::Direction direction) : - media::Media(parent, direction), d_ptr(new MediaAudioPrivate()) -{ - Q_ASSERT(parent); -} - -media::Media::Type media::Audio::type() -{ - return media::Media::Type::AUDIO; -} - -bool media::Audio::mute() -{ - CallManagerInterface& callManager = CallManager::instance(); - return callManager.muteLocalMedia(call()->dringId(), DRing::Media::Details::MEDIA_TYPE_AUDIO,true); -} - -bool media::Audio::unmute() -{ - CallManagerInterface& callManager = CallManager::instance(); - return callManager.muteLocalMedia(call()->dringId(), DRing::Media::Details::MEDIA_TYPE_AUDIO,false); -} - -media::Audio::~Audio() -{ - delete d_ptr; -} \ No newline at end of file diff --git a/src/media/audio.h b/src/media/audio.h deleted file mode 100644 index dd5b21d4d12fdd9373febd74cc8a296596b5c274..0000000000000000000000000000000000000000 --- a/src/media/audio.h +++ /dev/null @@ -1,46 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <media/media.h> -#include <typedefs.h> - -class MediaAudioPrivate; -class Call; -class CallPrivate; - -namespace media { - -class LIB_EXPORT Audio : public media::Media -{ - friend class ::CallPrivate; -public: - - virtual Media::Type type() override; - virtual bool mute() override; - virtual bool unmute() override; - -private: - Audio(Call* parent, const Media::Direction direction); - virtual ~Audio(); - - MediaAudioPrivate* d_ptr; -}; - -} - diff --git a/src/media/avrecording.cpp b/src/media/avrecording.cpp deleted file mode 100644 index b1d8be21495322298bc9f2cd25dcd41a74706f70..0000000000000000000000000000000000000000 --- a/src/media/avrecording.cpp +++ /dev/null @@ -1,293 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "avrecording.h" - -//DRing -#include "dbus/callmanager.h" - -//Ring -#include <callmodel.h> - -namespace media { - -class AVRecordingPrivate { -public: - AVRecordingPrivate(AVRecording* r); - - //Attributes - QUrl m_Path ; - AVRecording::Position m_Position; - int m_Duration; - bool m_IsPaused; - int m_Elapsed ; - int m_Left ; - - //Constants - constexpr static const char minutes[] = "%1:%2"; - constexpr static const char hours [] = "%1:%2:%3"; - - //Helper - void notifySeek(int position, int size); - -private: - AVRecording* q_ptr; -}; - - -constexpr const char AVRecordingPrivate::minutes[]; -constexpr const char AVRecordingPrivate::hours []; - -} - - -/** - * Keep track of currently active recordings - */ -class RecordingPlaybackManager : public QObject -{ - Q_OBJECT -public: - RecordingPlaybackManager(); - - //Attributes - QList<media::AVRecording*> m_lActiveRecordings; - QHash<QString, media::AVRecording*> m_hActiveRecordings; - - //Mutator - void activateRecording (media::AVRecording* r); - void desactivateRecording(media::AVRecording* r); - - //Singleton - static RecordingPlaybackManager& instance(); - -public Q_SLOTS: - void slotRecordPlaybackFilepath(const QString& callID, const QString& filepath ); - void slotRecordPlaybackStopped (const QString& filepath ); - void slotUpdatePlaybackScale (const QString& filepath, int position, int size); -}; - -RecordingPlaybackManager::RecordingPlaybackManager() : QObject() -{ - CallManagerInterface& callManager = CallManager::instance(); - connect(&callManager,&CallManagerInterface::recordPlaybackStopped , this, &RecordingPlaybackManager::slotRecordPlaybackStopped ); - connect(&callManager,&CallManagerInterface::updatePlaybackScale , this, &RecordingPlaybackManager::slotUpdatePlaybackScale ); - connect(&callManager,&CallManagerInterface::recordPlaybackFilepath, this, &RecordingPlaybackManager::slotRecordPlaybackFilepath); -} - -///Singleton -RecordingPlaybackManager& RecordingPlaybackManager::instance() -{ - static auto instance = new RecordingPlaybackManager; - return *instance; -} - - -media::AVRecordingPrivate::AVRecordingPrivate(AVRecording* r) : q_ptr(r),m_Position(0.0),m_Duration(0),m_IsPaused(false), -m_Elapsed(0),m_Left(0) -{ - -} - -media::AVRecording::AVRecording() : Recording(Recording::Type::AUDIO_VIDEO), d_ptr(new AVRecordingPrivate(this)) -{ -} - -media::AVRecording::~AVRecording() -{ - delete d_ptr; -} - -///Return this recording path, if any -QUrl media::AVRecording::path() const -{ - return d_ptr->m_Path; -} - -///Get the current playback position (0.0 if not playing) -media::AVRecording::Position media::AVRecording::position() const -{ - return d_ptr->m_Position; -} - -/** - * Recording duration (in seconds). This is only available for audio/video - * recordings and only after playback started. - */ -int media::AVRecording::duration() const -{ - return d_ptr->m_Duration; -} - -#define FORMATTED_TIME_MACRO(var) if (d_ptr->m_Duration > 3599) {\ - return QString(AVRecordingPrivate::hours)\ - .arg(var/3600 )\ - .arg((var%3600)/60,2,10,QChar('0'))\ - .arg(var%60,2,10,QChar('0') );\ - }\ - else {\ - return QString(AVRecordingPrivate::minutes)\ - .arg(var/60,2,10,QChar('0'))\ - .arg(var%60,2,10,QChar('0'));\ - } - -///Get the a string in format hhh:mm:ss for the time elapsed since the playback started -QString media::AVRecording::formattedTimeElapsed() const -{ - FORMATTED_TIME_MACRO(d_ptr->m_Elapsed); -} - -///Get the a string in format hhh:mm:ss for the total time of this recording -QString media::AVRecording::formattedDuration() const -{ - FORMATTED_TIME_MACRO(d_ptr->m_Duration); -} - -///Get the a string in format hhh:mm:ss for the time elapsed before the playback end -QString media::AVRecording::formattedTimeLeft() const -{ - FORMATTED_TIME_MACRO(d_ptr->m_Left); -} -#undef FORMATTED_TIME_MACRO - -void media::AVRecording::setPath(const QUrl& path) -{ - d_ptr->m_Path = path; -} - -///Play (or resume) the playback -void media::AVRecording::play() -{ - RecordingPlaybackManager::instance().activateRecording(this); - - CallManagerInterface& callManager = CallManager::instance(); - const bool retval = callManager.startRecordedFilePlayback(path().path()); - if (retval) - emit started(); - - if (d_ptr->m_IsPaused) { - seek(d_ptr->m_Position); - d_ptr->m_IsPaused = false; - } -} - -///Stop the playback, cancel any pause point -void media::AVRecording::stop() -{ - CallManagerInterface& callManager = CallManager::instance(); - Q_NOREPLY callManager.stopRecordedFilePlayback(); - emit stopped(); - - RecordingPlaybackManager::instance().desactivateRecording(this); - d_ptr->m_IsPaused = false; -} - -///Pause (or resume) -void media::AVRecording::pause() -{ - if (d_ptr->m_IsPaused) { - play(); - } - else { - stop(); - d_ptr->m_IsPaused = true; - } -} - -/** - * Change position in this recording - * @note only available during playback - * @args pos The position, in percent - */ -void media::AVRecording::seek(AVRecording::Position pos) -{ - CallManagerInterface& callManager = CallManager::instance(); - Q_NOREPLY callManager.recordPlaybackSeek(pos); -} - -///Move the playback position to the origin -void media::AVRecording::reset() -{ - seek(0.0); -} - -///Update all internal playback metadatas -void media::AVRecordingPrivate::notifySeek(int position, int size) -{ - const int oldElapsed = m_Elapsed ; - const int oldDuration = m_Duration; - - //Update the metadata - m_Duration = size/1000; - m_Position = ((double)position)/((double)size); - m_Elapsed = m_Duration * static_cast<int>(m_Position); - m_Left = m_Duration - m_Elapsed ; - - if (oldDuration != m_Duration) - emit q_ptr->formattedDurationChanged(q_ptr->formattedDuration()); - - if (oldElapsed != m_Elapsed) { - emit q_ptr->formattedTimeElapsedChanged(q_ptr->formattedTimeElapsed()); - emit q_ptr->formattedTimeLeftChanged (q_ptr->formattedTimeLeft ()); - } - - emit q_ptr->playbackPositionChanged(m_Position); -} - -///Callback when a recording start -void RecordingPlaybackManager::slotRecordPlaybackFilepath(const QString& callID, const QString& filepath) -{ - //TODO is this method dead code? - qDebug() << "Playback started" << callID << filepath; -} - -///Callback when a recording stop -void RecordingPlaybackManager::slotRecordPlaybackStopped(const QString& filepath) -{ - media::AVRecording* r = m_hActiveRecordings[filepath]; - if (r) { - desactivateRecording(r); - } -} - -///Callback when a recording position changed -void RecordingPlaybackManager::slotUpdatePlaybackScale(const QString& filepath, int position, int size) -{ - media::AVRecording* r = m_hActiveRecordings[filepath]; - - if (r) { - r->d_ptr->notifySeek(position, size); - } - else - qDebug() << "Unregistered recording position changed" << filepath; -} - -///To avoid having to keep a list of all recording, manage a small active recording list -void RecordingPlaybackManager::activateRecording(media::AVRecording* r) -{ - m_lActiveRecordings << r; - m_hActiveRecordings[r->path().path()] = r; -} - -///To avoid having to keep a list of all recording, manage a small active recording list -void RecordingPlaybackManager::desactivateRecording(media::AVRecording* r) -{ - m_lActiveRecordings.removeAll(r); - m_hActiveRecordings.remove(m_hActiveRecordings.key(r)); -} - -#include <avrecording.moc> diff --git a/src/media/avrecording.h b/src/media/avrecording.h deleted file mode 100644 index c40b8b30c8e25d49e4f3f632993e0e2e4829d719..0000000000000000000000000000000000000000 --- a/src/media/avrecording.h +++ /dev/null @@ -1,91 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <media/recording.h> - -#include <QtCore/QUrl> - -namespace media { - -class AVRecordingPrivate; - -class LIB_EXPORT AVRecording : public Recording -{ - Q_OBJECT - - friend class ::RecordingPlaybackManager; -public: - //Types - typedef double Position; - - //Properties - Q_PROPERTY( QUrl path READ path ) - Q_PROPERTY( AVRecording::Position position READ position ) - Q_PROPERTY( int duration READ duration ) - Q_PROPERTY( QString formattedTimeElapsed READ formattedTimeElapsed NOTIFY formattedTimeElapsedChanged) - Q_PROPERTY( QString formattedDuration READ formattedDuration NOTIFY formattedDurationChanged ) - Q_PROPERTY( QString formattedTimeLeft READ formattedTimeLeft NOTIFY formattedTimeLeftChanged ) - - //Constructor - explicit AVRecording(); - virtual ~AVRecording(); - - //Getter - QUrl path () const; - AVRecording::Position position () const; - int duration () const; - QString formattedTimeElapsed() const; - QString formattedDuration () const; - QString formattedTimeLeft () const; - - //Setter - void setPath(const QUrl& path); - -private: - AVRecordingPrivate* d_ptr; - Q_DECLARE_PRIVATE(AVRecording) - -public Q_SLOTS: - void play ( ); - void stop ( ); - void pause( ); - void seek ( AVRecording::Position pos ); - void reset( ); - -Q_SIGNALS: - /** - * The recording playback position changed - * @args pos The position, in percent - */ - void playbackPositionChanged(AVRecording::Position pos); - ///The recording playback has stopped - void stopped(); - ///The recording playback has started - void started(); - ///Emitted when the formatted elapsed time string change - void formattedTimeElapsedChanged(const QString& formattedValue); - ///Emitted when the formatted duration string change - void formattedDurationChanged (const QString& formattedValue); - ///Emitted when the formatted time left string change - void formattedTimeLeftChanged (const QString& formattedValue); - -}; - -} - diff --git a/src/media/file.cpp b/src/media/file.cpp deleted file mode 100644 index 0d07debda4d30c3c423ea032e664ac99d28541b2..0000000000000000000000000000000000000000 --- a/src/media/file.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "file.h" - -//Dring -#include <media_const.h> -#include "dbus/callmanager.h" - -//Ring -#include <call.h> - -class MediaFilePrivate -{ -}; - -media::File::File(Call* parent, const Media::Direction direction) : media::Media(parent, direction), d_ptr(new MediaFilePrivate()) -{ - Q_ASSERT(parent); -} - -media::Media::Type media::File::type() -{ - return media::Media::Type::FILE; -} - -media::File::~File() -{ - delete d_ptr; -} \ No newline at end of file diff --git a/src/media/file.h b/src/media/file.h deleted file mode 100644 index 9adea7651676b5aa57ee5ccf11a469c86de47a9a..0000000000000000000000000000000000000000 --- a/src/media/file.h +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <media/media.h> -#include <typedefs.h> - -class MediaFilePrivate; -class Call; -class CallPrivate; - -namespace media { - -class LIB_EXPORT File : public media::Media -{ - friend class ::CallPrivate; -public: - - virtual Media::Type type() override; - -private: - File(Call* parent, const Media::Direction direction); - virtual ~File(); - - MediaFilePrivate* d_ptr; -}; - -} - diff --git a/src/media/media.cpp b/src/media/media.cpp deleted file mode 100644 index 12f3a785bc498319354c963fd84bad0828a6d3a4..0000000000000000000000000000000000000000 --- a/src/media/media.cpp +++ /dev/null @@ -1,166 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "media.h" - -#include "../private/media_p.h" -#include <call.h> - -const Matrix2D<media::Media::State, media::Media::Action, bool> media::MediaPrivate::m_mValidTransitions ={{ - /* MUTE UNMUTE TERMINATE */ - /* ACTIVE */ {{ true , true , true }}, - /* MUTED */ {{ true , true , true }}, - /* IDLE */ {{ true , false , true }}, - /* OVER */ {{ false , false , false }}, -}}; - -//Use the Media::MediaPrivate wrapper to avoid vtable issues -#define MEDF &MediaPrivate -const Matrix2D<media::Media::State, media::Media::Action, media::MediaTransitionFct> media::MediaPrivate::m_mCallbacks ={{ - /* MUTE UNMUTE TERMINATE */ - /* ACTIVE */ {{ MEDF::mute , MEDF::nothing , MEDF::terminate }}, - /* MUTED */ {{ MEDF::nothing , MEDF::unmute , MEDF::terminate }}, - /* IDLE */ {{ MEDF::mute , MEDF::nothing , MEDF::terminate }}, - /* OVER */ {{ MEDF::nothing , MEDF::nothing , MEDF::nothing }}, -}}; -#undef MEDF - -namespace media { - -MediaPrivate::MediaPrivate(Media* parent) : - m_State(media::Media::State::ACTIVE),m_pCall(nullptr),q_ptr(parent),m_Direction(Media::Direction::OUT) -{ - -} - -media::Media::Media(Call* parent, const media::Media::Direction dir) : - QObject(parent), d_ptr(new MediaPrivate(this)) -{ - Q_ASSERT(parent); - d_ptr->m_pCall = parent; - d_ptr->m_Direction = dir; -} - -media::Media::~Media() -{ - delete d_ptr; -} - -} - -/** - * Method to be re-implemented by each concrete media classes - * - * This can (and should) be performed asynchronously - * - * @return if the operation has already failed - */ -bool media::Media::mute() -{ - return false; -} - -bool media::Media::unmute() -{ - return false; -} - -bool media::Media::terminate() -{ - return false; -} - -bool media::MediaPrivate::mute() -{ - return q_ptr->mute(); -} - -bool media::MediaPrivate::unmute() -{ - return q_ptr->unmute(); -} - -bool media::MediaPrivate::terminate() -{ - return q_ptr->terminate(); -} - -bool media::MediaPrivate::nothing() -{ - return true; -} - -Call* media::Media::call() const -{ - return d_ptr->m_pCall; -} - -media::Media::Direction media::Media::direction() const -{ - return d_ptr->m_Direction; -} - -media::Media::State media::Media::state() const -{ - return d_ptr->m_State; -} - -bool media::Media::performAction(const media::Media::Action action) -{ - const media::Media::State s = d_ptr->m_State; - - //TODO implement a state machine - const bool ret = (d_ptr->*(d_ptr->m_mCallbacks)[d_ptr->m_State][action])(); - - if (d_ptr->m_State != s && ret) { - emit stateChanged(d_ptr->m_State, s); - } - - return ret; -} - -media::Media* operator<<(media::Media* m, media::Media::Action a) -{ - m->performAction(a); - return m; -} - -void media::MediaPrivate::muteConfirmed() -{ - const auto ll = m_State; - m_State = media::Media::State::MUTED; - emit q_ptr->stateChanged(m_State, ll); -} - -void media::MediaPrivate::unmuteConfirmed() -{ - const auto ll = m_State; - switch(q_ptr->type()) { - case media::Media::Type::AUDIO: - case media::Media::Type::VIDEO: - case media::Media::Type::FILE: - m_State = media::Media::State::ACTIVE; - emit q_ptr->stateChanged(m_State, ll); - break; - case media::Media::Type::TEXT: - m_State = media::Media::State::IDLE; - emit q_ptr->stateChanged(m_State, ll); - break; - case media::Media::Type::COUNT__: - break; - }; -} diff --git a/src/media/media.h b/src/media/media.h deleted file mode 100644 index 97b407284ce495d73020311986a383c7df87ab9f..0000000000000000000000000000000000000000 --- a/src/media/media.h +++ /dev/null @@ -1,104 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#include "typedefs.h" - -class Call; - -namespace media { - class MediaPrivate; -} - -namespace media { - -class LIB_EXPORT Media : public QObject -{ - Q_OBJECT -public: - enum class Type { - AUDIO = 0, /*!< */ - VIDEO = 1, /*!< */ - TEXT = 2, /*!< */ - FILE = 3, /*!< */ - COUNT__ - }; - - enum class State { - ACTIVE = 0, /*!< The media is currently in progress */ - MUTED = 1, /*!< The media has been paused */ - IDLE = 2, /*!< The media is passive, but in progress */ - OVER = 3, /*!< The media is terminated */ - COUNT__ - }; - - enum class Direction { - #pragma push_macro("OUT") - #pragma push_macro("IN") - #undef OUT - #undef IN - IN , /*!< The media is coming from the peer */ - OUT, /*!< The media is going to the peer */ - COUNT__ - #pragma pop_macro("OUT") - #pragma pop_macro("IN") - }; - - enum class Action { - MUTE , /*!< Mute this media */ - UNMUTE , /*!< Unmute this media */ - TERMINATE, /*!< End this media */ - COUNT__ - }; - - //Getter - virtual Media::Type type() = 0; - Call* call() const; - Direction direction() const; - - //Getters - media::Media::State state() const; - bool performAction(const Media::Action); - - //TODO add an abstract history getter with specialisation per media - - virtual ~Media(); - -protected: - - //Protected mutators - virtual bool mute(); - virtual bool unmute(); - virtual bool terminate(); - - Media(Call* parent, const Direction direction); - -Q_SIGNALS: - void stateChanged(const Media::State state, const Media::State previous); - -private: - MediaPrivate* d_ptr; - Q_DECLARE_PRIVATE(Media) -}; - -} -Q_DECLARE_METATYPE(media::Media::Direction) - -media::Media* operator<<(media::Media* m, media::Media::Action a); diff --git a/src/media/recording.cpp b/src/media/recording.cpp deleted file mode 100644 index 4ec01cf4896dcb3492af08fc6b356a9918905485..0000000000000000000000000000000000000000 --- a/src/media/recording.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "recording.h" - -namespace media { - -class RecordingPrivate { -public: - RecordingPrivate(Recording* r); - - //Attributes - Recording::Type m_Type ; - Call* m_pCall ; - -private: - Recording* q_ptr; -}; - -RecordingPrivate::RecordingPrivate(Recording* r) : q_ptr(r),m_pCall(nullptr) -{ - -} - -Recording::Recording(const Recording::Type type) : ItemBase(nullptr), d_ptr(new RecordingPrivate(this)) -{ - d_ptr->m_Type = type; -} - -Recording::~Recording() -{ - delete d_ptr; -} - -} //Media:: - -///Return this Recording type -media::Recording::Type media::Recording::type() const -{ - return d_ptr->m_Type; -} - -Call* media::Recording::call() const -{ - return d_ptr->m_pCall; -} - -void media::Recording::setCall(Call* call) -{ - d_ptr->m_pCall = call; -} - -#include <recording.moc> diff --git a/src/media/recording.h b/src/media/recording.h deleted file mode 100644 index 66490f7630ef957ad5c736003be05816c2e7ebe0..0000000000000000000000000000000000000000 --- a/src/media/recording.h +++ /dev/null @@ -1,66 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> -#include <itembase.h> - -#include <typedefs.h> - -class RecordingPlaybackManager; -class Call; - -namespace media { - -class RecordingPrivate; - -/** - * @class Recording a representation of one or more media recording - */ -class LIB_EXPORT Recording : public ItemBase -{ - Q_OBJECT - -public: - - //Properties - Q_PROPERTY( Recording::Type type READ type ) - - enum class Type { - AUDIO_VIDEO, /*!< The recording is a single file, playable by the daemon */ - TEXT , /*!< The recording is an encoded text stream and a position */ - /*FILE*/ - }; - - //Constructor - explicit Recording(const Recording::Type type); - virtual ~Recording(); - - //Getter - Recording::Type type() const; - Call* call() const; - - //Setter - void setCall(Call* call); - -private: - RecordingPrivate* d_ptr; - Q_DECLARE_PRIVATE(Recording) -}; - -} diff --git a/src/media/recordingmodel.cpp b/src/media/recordingmodel.cpp deleted file mode 100644 index df46c6b10f5b0abecbaaba48720fe84fd983734b..0000000000000000000000000000000000000000 --- a/src/media/recordingmodel.cpp +++ /dev/null @@ -1,348 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "recordingmodel.h" - -//Qt -#include <QtCore/QMimeData> -#include <QtCore/QCoreApplication> -#include <QtCore/QUrl> - -//Ring -#include "recording.h" -#include "media.h" - -//DRing -#include "dbus/configurationmanager.h" - -struct RecordingNode final -{ - ~RecordingNode(); - - enum class Type { - TOP_LEVEL, - SESSION , - TAG , - }; - - RecordingNode(RecordingNode::Type type); - - //Attributes - RecordingNode::Type m_Type ; - int m_Index ; - QString m_CatName ; - media::Recording* m_pRec ; - QVector<RecordingNode*> m_lChildren; - RecordingNode* m_pParent ; - -}; - -class RecordingModelPrivate final : public QObject -{ - Q_OBJECT -public: - explicit RecordingModelPrivate(media::RecordingModel* parent); - ~RecordingModelPrivate(); - - //Attributes - QVector<RecordingNode*> m_lCategories ; - RecordingNode* m_pText {nullptr}; - RecordingNode* m_pAudioVideo {nullptr}; - int m_UnreadCount { 0 }; - - //RecordingNode* m_pFiles ; //TODO uncomment when implemented in DRing - - void forwardInsertion(const QMap<QString,QString>& message, ContactMethod* cm, media::Media::Direction direction); - void updateUnreadCount(const int count); - -private: - media::RecordingModel* q_ptr; -}; - -RecordingNode::RecordingNode(RecordingNode::Type type) : - m_Type(type),m_pParent(nullptr), m_pRec(nullptr), m_Index(-1) -{ - -} - -RecordingNode::~RecordingNode() -{ - foreach(RecordingNode* c, m_lChildren) - delete c; -} - -RecordingModelPrivate::RecordingModelPrivate(media::RecordingModel* parent) : q_ptr(parent),m_pText(nullptr), -m_pAudioVideo(nullptr)/*,m_pFiles(nullptr)*/ -{ - -} - -RecordingModelPrivate::~RecordingModelPrivate() -{ - if (m_pText) - delete m_pText; - - if (m_pAudioVideo) - delete m_pAudioVideo; -} - -void RecordingModelPrivate::forwardInsertion(const QMap<QString,QString>& message, ContactMethod* cm, media::Media::Direction direction) -{ - Q_UNUSED(message) - Q_UNUSED(direction) -} - -void RecordingModelPrivate::updateUnreadCount(const int count) -{ - m_UnreadCount += count; - if (m_UnreadCount <= 0) { - m_UnreadCount = 0; - } - emit q_ptr->unreadMessagesCountChanged(m_UnreadCount); -} - -media::RecordingModel::~RecordingModel() -{ - delete d_ptr; -} - -media::RecordingModel::RecordingModel(QObject* parent) : QAbstractItemModel(parent), CollectionManagerInterface<Recording>(this), -d_ptr(new RecordingModelPrivate(this)) -{ - setObjectName("RecordingModel"); -} - -media::RecordingModel& media::RecordingModel::instance() -{ - static auto instance = new RecordingModel(QCoreApplication::instance()); - return *instance; -} - -QHash<int,QByteArray> media::RecordingModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - }*/ - return roles; -} - -//Do nothing -bool media::RecordingModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -///Get bookmark model data RecordingNode::Type and Call::Role -QVariant media::RecordingModel::data( const QModelIndex& index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - //RecordingNode* modelItem = static_cast<RecordingNode*>(index.internalPointer()); - - switch (role) { - case Qt::DisplayRole: - return "foo"; - } - - return QVariant(); -} - -///Get header data -QVariant media::RecordingModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(section) - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return QVariant(tr("Recordings")); - return QVariant(); -} - -///Get the number of child of "parent" -int media::RecordingModel::rowCount( const QModelIndex& parent ) const -{ - if (!parent.isValid()) - return d_ptr->m_lCategories.size(); - else { - const RecordingNode* modelItem = static_cast<RecordingNode*>(parent.internalPointer()); - return modelItem->m_lChildren.size(); - } -} - -Qt::ItemFlags media::RecordingModel::flags( const QModelIndex& index ) const -{ - if (!index.isValid()) - return Qt::NoItemFlags; - - return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEnabled; -} - -///There is only 1 column -int media::RecordingModel::columnCount ( const QModelIndex& parent) const -{ - Q_UNUSED(parent) - return 1; -} - -///Get the bookmark parent -QModelIndex media::RecordingModel::parent( const QModelIndex& idx) const -{ - if (!idx.isValid()) - return QModelIndex(); - - RecordingNode* modelItem = static_cast<RecordingNode*>(idx.internalPointer()); - - if (modelItem->m_Type == RecordingNode::Type::SESSION) { - RecordingNode* item = static_cast<RecordingNode*>(modelItem)->m_pParent; - - if (item) - return createIndex(item->m_Index,0,item); - - } - - return QModelIndex(); -} //parent - -///Get the index -QModelIndex media::RecordingModel::index(int row, int column, const QModelIndex& parent) const -{ - if (column || (!parent.isValid() && row >= d_ptr->m_lCategories.size())) - return QModelIndex(); - - const RecordingNode* modelItem = parent.isValid() ? static_cast<const RecordingNode*>(parent.internalPointer()) : d_ptr->m_lCategories[row]; - - if (row >= modelItem->m_lChildren.size()) - return QModelIndex(); - - return createIndex(row,0,modelItem->m_lChildren[row]); -} - -bool media::RecordingModel::addItemCallback(const Recording* item) -{ - Q_UNUSED(item) - - //Create some categories - if (d_ptr->m_lCategories.size() == 0) { - d_ptr->m_pText = new RecordingNode(RecordingNode::Type::TOP_LEVEL); - d_ptr->m_pText->m_CatName = tr("Text messages"); - d_ptr->m_pText->m_Index = 0; - d_ptr->m_lCategories << d_ptr->m_pText; - - d_ptr->m_pAudioVideo = new RecordingNode(RecordingNode::Type::TOP_LEVEL); - d_ptr->m_pAudioVideo->m_CatName = tr("Audio/Video"); - d_ptr->m_pAudioVideo->m_Index = 1; - d_ptr->m_lCategories << d_ptr->m_pAudioVideo; - - /*d_ptr->m_pFiles = new RecordingNode(RecordingNode::Type::TOP_LEVEL); - d_ptr->m_pFiles->m_CatName = tr("Files"); - d_ptr->m_pFiles->m_Index = 2; - d_ptr->m_lCategories << m_pFiles;*/ - } - - //Categorize by general media group - RecordingNode* parent = nullptr; - - if (item->type() == Recording::Type::TEXT) - parent = d_ptr->m_pText; - else if (item->type() == Recording::Type::AUDIO_VIDEO) - parent = d_ptr->m_pAudioVideo; - /*else if (item->type() == Recording::Type::FILE)) - parent = d_ptr->m_pFiles;*/ - - //Insert the item - if (parent) { - - beginInsertRows(index(parent->m_Index,0),parent->m_lChildren.size(),parent->m_lChildren.size()); - - RecordingNode* n = new RecordingNode ( RecordingNode::Type::SESSION ); - n->m_pRec = const_cast<Recording*> ( item ); - n->m_Index = parent->m_lChildren.size( ); - parent->m_lChildren << n; - - endInsertRows(); - - return true; - } - - return false; -} - -bool media::RecordingModel::removeItemCallback(const Recording* item) -{ - Q_UNUSED(item) - return false; -} - -bool media::RecordingModel::clearAllCollections() const -{ - foreach (CollectionInterface* backend, collections(CollectionInterface::SupportedFeatures::CLEAR)) { - backend->clear(); - } - return true; -} - -///Deletes all recordings (which are possible to delete) and clears model -void media::RecordingModel::clear() -{ - beginResetModel(); - clearAllCollections(); - endResetModel(); -} - -void media::RecordingModel::collectionAddedCallback(CollectionInterface* backend) -{ - Q_UNUSED(backend) -} - -///Set where the call recordings will be saved -void media::RecordingModel::setRecordPath(const QString& path) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setRecordPath(path); -} - -///Return the path where recordings are going to be saved -QString media::RecordingModel::recordPath() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return configurationManager.getRecordPath(); -} - -///are all calls recorded by default -bool media::RecordingModel::isAlwaysRecording() const -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - return configurationManager.getIsAlwaysRecording(); -} - -///Set if all calls needs to be recorded -void media::RecordingModel::setAlwaysRecording(bool record) -{ - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - configurationManager.setIsAlwaysRecording ( record ); -} - -int media::RecordingModel::unreadCount() const -{ - return d_ptr->m_UnreadCount; -} - -#include <recordingmodel.moc> diff --git a/src/media/recordingmodel.h b/src/media/recordingmodel.h deleted file mode 100644 index 4f0ed990090990d553a8348dc454b313aefc1664..0000000000000000000000000000000000000000 --- a/src/media/recordingmodel.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractItemModel> -#include <QtCore/QHash> -#include <QtCore/QStringList> - -//Ring -#include "collectionmanagerinterface.h" -#include "collectioninterface.h" -#include "typedefs.h" -#include "contactmethod.h" - -class RecordingModelPrivate; -class ContactMethod; - -namespace media { - class Recording; - class AVRecording; - -/** - * This model host the Ring recordings. Recording sessions span one or - * more media, themselves possibly spanning multiple communications. They - * can be paused indefinitely and resumed. Those events cause the recording - * to be tagged at a specific point. - * - * The purpose of this model is mostly to track the recordings and handle - * housekeeping task. It could also be used to manage recordings, move them - * and so on. - */ -class LIB_EXPORT RecordingModel : public QAbstractItemModel, public CollectionManagerInterface<Recording> -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop -public: - - //Constructor - virtual ~RecordingModel(); - explicit RecordingModel(QObject* parent); - - virtual bool clearAllCollections() const override; - - //Model implementation - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Getter - bool isAlwaysRecording() const; - QString recordPath () const; - int unreadCount () const; - - //Setter - void setAlwaysRecording( bool record ); - void setRecordPath ( const QString& path ); - void clear ( ); - - //Singleton - static RecordingModel& instance(); - -Q_SIGNALS: - void unreadMessagesCountChanged(int unreadCount); - -private: - RecordingModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(RecordingModel) - - //Collection interface - virtual void collectionAddedCallback(CollectionInterface* backend) override; - virtual bool addItemCallback (const Recording* item ) override; - virtual bool removeItemCallback (const Recording* item ) override; -}; - -} diff --git a/src/media/text.cpp b/src/media/text.cpp deleted file mode 100644 index 0020c37ad2b7dcaaadc0cf88b8e577526cfb5b23..0000000000000000000000000000000000000000 --- a/src/media/text.cpp +++ /dev/null @@ -1,232 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "text.h" - -//Dring -#include <media_const.h> -#include "dbus/callmanager.h" -#include "dbus/configurationmanager.h" - -//Ring -#include <call.h> -#include <account.h> -#include <person.h> -#include <contactmethod.h> -#include <mime.h> -#include <media/recordingmodel.h> -#include <phonedirectorymodel.h> -#include <private/call_p.h> -#include <private/vcardutils.h> -#include <private/imconversationmanagerprivate.h> -#include <accountmodel.h> -#include <personmodel.h> - -/* - * Instant message have 3 major modes, "past", "in call" and "offline" - * - * Offline messages are currently implemented over the DHT and may eventually - * be implemented over account registration (publish--subscribe) - * - * In call messages are the fastest as they have a communication channels of their - * own. - * - * Past messages are local copy of past communication stored somewhere. - * - * All 3 sources have to be combined dynamically into a single stream per person. - * - * So chunks can come from all 3 sources for the same stream, including part that - * are shared in a conference with multiple peers. - */ - -class MediaTextPrivate -{ -public: - MediaTextPrivate(media::Text* parent); - - //Attributes - bool m_HasChecked; - QHash<QString,bool> m_hMimeTypes; - QStringList m_lMimeTypes; - - //Helper - void updateMimeList(const QMap<QString,QString>& payloads); - -private: - media::Text* q_ptr; -}; - -class ProfileChunk -{ -public: - //Helper - static Person* addChunk( const QMap<QString,QString>& args, const QString& payload, ContactMethod *contactMethod); - -private: - //Attributes - QHash<int, QString> m_hParts { }; - int m_PartsCount { 0 }; - static QHash<QString, ProfileChunk*> m_hRequest; -}; - -QHash<QString, ProfileChunk*> ProfileChunk::m_hRequest; - -IMConversationManagerPrivate::IMConversationManagerPrivate(QObject* parent) : QObject(parent) -{ - CallManagerInterface& callManager = CallManager::instance(); - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - connect(&configurationManager, &ConfigurationManagerInterface::incomingAccountMessage, this, &IMConversationManagerPrivate::newAccountMessage); - connect(&configurationManager, &ConfigurationManagerInterface::accountMessageStatusChanged , this, &IMConversationManagerPrivate::accountMessageStatusChanged); - connect(&callManager , &CallManagerInterface::incomingMessage , this, &IMConversationManagerPrivate::newMessage ); -} - -IMConversationManagerPrivate& IMConversationManagerPrivate::instance() -{ - static auto instance = new IMConversationManagerPrivate(nullptr); - return *instance; -} - -Person* ProfileChunk::addChunk(const QMap<QString, QString>& args, const QString& payload, ContactMethod *contactMethod) -{ - const int total = args[ "of" ].toInt(); - const int part = args[ "part" ].toInt(); - const QString id = args[ "id" ]; - - auto c = m_hRequest[id]; - if (!c) { - c = new ProfileChunk(); - c->m_PartsCount = total; - m_hRequest[id] = c; - } - - if (part < 1 and part > total) - return nullptr; - - c->m_hParts[part] = payload; - - if (c->m_hParts.size() != c->m_PartsCount) - return nullptr; - - QByteArray cv; - for (int i=0; i < c->m_PartsCount; ++i) { - cv += c->m_hParts[i+1]; - } - - m_hRequest[id] = nullptr; - delete c; - - return VCardUtils::mapToPersonFromReceivedProfile(contactMethod, cv); -} - -///Called when a new message is incoming -void IMConversationManagerPrivate::newMessage(const QString& callId, const QString& from, const QMap<QString,QString>& message) -{ - return; -} - -void IMConversationManagerPrivate::newAccountMessage(const QString& accountId, const QString& from, const QMap<QString,QString>& payloads) -{ -} - -void IMConversationManagerPrivate::accountMessageStatusChanged(const QString& accountId, uint64_t id, const QString& to, int status) -{ -} - -MediaTextPrivate::MediaTextPrivate(media::Text* parent) : q_ptr(parent),m_HasChecked(false) -{ -} - -media::Text::Text(Call* parent, const Media::Direction direction) : media::Media(parent, direction), d_ptr(new MediaTextPrivate(this)) -{ - Q_ASSERT(parent); -} - -media::Media::Type media::Text::type() -{ - return media::Media::Type::TEXT; -} - -media::Text::~Text() -{ - delete d_ptr; -} - - -bool media::Text::hasMimeType( const QString& mimeType ) const -{ - return d_ptr->m_hMimeTypes.contains(mimeType); -} - -QStringList media::Text::mimeTypes() const -{ - return d_ptr->m_lMimeTypes; -} - - -void MediaTextPrivate::updateMimeList(const QMap<QString,QString>& payloads) -{ - const int prevSize = m_hMimeTypes.size(); - - QMapIterator<QString, QString> iter(payloads); - - while (iter.hasNext()) { - iter.next(); - - // Mime types can have some arguments after ';' - const QString mimeType = iter.key(); - const int hasArgs = mimeType.indexOf(';'); - const QString strippedMimeType = hasArgs != -1 ? mimeType.left(hasArgs) : mimeType; - const int currentSize = m_hMimeTypes.size(); - - m_hMimeTypes[strippedMimeType] = true; - - if (currentSize != m_hMimeTypes.size()) - m_lMimeTypes << strippedMimeType; - } - - if (prevSize != m_hMimeTypes.size()) - emit q_ptr->mimeTypesChanged(); - -} - -/** - * Send a message to the peer. - * - * @param message A messages encoded in various alternate payloads - * - * The send a single messages. Just as e-mails, the message can be - * encoded differently. The peer client will interpret the richest - * payload it support and then fallback to lesser ones. - * - * Suggested payloads include: - * - * "text/plain" : The most common plain UTF-8 text - * "text/enriched" : (RTF) The rich text format used by older applications (like WordPad and OS X TextEdit) - * "text/html" : The format used by web browsers - */ -void media::Text::send(const QMap<QString,QString>& message, const bool isMixed) -{ - CallManagerInterface& callManager = CallManager::instance(); - Q_NOREPLY callManager.sendTextMessage(call()->dringId(), message, isMixed); - - d_ptr->updateMimeList(message); - - emit messageSent(message); -} - -#include <text.moc> diff --git a/src/media/text.h b/src/media/text.h deleted file mode 100644 index 7f113960584a752f4d6aa5c1c4e5277a74d2a5b3..0000000000000000000000000000000000000000 --- a/src/media/text.h +++ /dev/null @@ -1,59 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <media/media.h> -#include <typedefs.h> - -class MediaTextPrivate; -class Call; -class CallPrivate; -class InstantMessagingModel; -class IMConversationManagerPrivate; - -namespace media { - -class LIB_EXPORT Text : public media::Media -{ - Q_OBJECT - friend class ::CallPrivate; - friend class ::IMConversationManagerPrivate; -public: - - virtual Media::Type type() override; - - //Getter - bool hasMimeType ( const QString& mimeType ) const; - QStringList mimeTypes ( ) const; - - //Mutator - void send(const QMap<QString,QString>& message, const bool isMixed = false); - -private: - Text(Call* parent, const Media::Direction direction); - virtual ~Text(); - - MediaTextPrivate* d_ptr; - -Q_SIGNALS: - void messageSent (const QMap<QString,QString>& m); - void messageReceived(const QMap<QString,QString>& m); - void mimeTypesChanged(); -}; - -} diff --git a/src/media/textrecording.cpp b/src/media/textrecording.cpp deleted file mode 100644 index eec1351670d419b935e3f496bfa4bac8acbd4b0e..0000000000000000000000000000000000000000 --- a/src/media/textrecording.cpp +++ /dev/null @@ -1,953 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "textrecording.h" - -//Qt -#include <QtCore/QJsonObject> -#include <QtCore/QJsonArray> -#include <QtCore/QJsonValue> -#include <QtCore/QJsonDocument> -#include <QtCore/QDateTime> -#include <QtCore/QCryptographicHash> -#include <QtCore/QUrl> - -//Daemon -#include <account_const.h> - -//Ring -#include "callmodel.h" -#include "contactmethod.h" -#include "account.h" -#include "phonedirectorymodel.h" -#include "accountmodel.h" -#include "personmodel.h" -#include "private/textrecording_p.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "itemdataroles.h" -#include "mime.h" -#include "dbus/configurationmanager.h" - -//Std -#include <ctime> - -QHash<QByteArray, Serializable::Peers*> SerializableEntityManager::m_hPeers; - -void addPeer(Serializable::Peers* p, const ContactMethod* cm); -void addPeer(Serializable::Peers* p, const ContactMethod* cm) -{ - Serializable::Peer* peer = new Serializable::Peer(); - peer->sha1 = cm->sha1(); - peer->uri = cm->uri(); - peer->accountId = cm->account() ? cm->account()->id () : QString(); - peer->personUID = cm->contact() ? cm->contact()->uid() : QString(); - p->peers << peer; -} - -Serializable::Peers* SerializableEntityManager::peer(const ContactMethod* cm) -{ - const QByteArray sha1 = cm->sha1(); - Serializable::Peers* p = m_hPeers[sha1]; - - if (!p) { - p = new Serializable::Peers(); - p->sha1s << sha1; - - addPeer(p,cm); - - m_hPeers[sha1] = p; - } - - return p; -} - -QByteArray mashSha1s(QList<QString> sha1s); -QByteArray mashSha1s(QList<QString> sha1s) -{ - QCryptographicHash hash(QCryptographicHash::Sha1); - - QByteArray ps; - - for (const QString& sha1 : sha1s) { - ps += sha1.toLatin1(); - } - - hash.addData(ps); - - //Create a reproducible key for this file - return hash.result().toHex(); -} - -Serializable::Peers* SerializableEntityManager::peers(QList<const ContactMethod*> cms) -{ - QList<QString> sha1s; - - for(const ContactMethod* cm : cms) { - const QByteArray sha1 = cm->sha1(); - sha1s << sha1; - } - - const QByteArray sha1 = ::mashSha1s(sha1s); - - Serializable::Peers* p = m_hPeers[sha1]; - - if (!p) { - p = new Serializable::Peers(); - p->sha1s = sha1s; - m_hPeers[sha1] = p; - } - - return p; -} - -Serializable::Peers* SerializableEntityManager::fromSha1(const QByteArray& sha1) -{ - return m_hPeers[sha1]; -} - -Serializable::Peers* SerializableEntityManager::fromJson(const QJsonObject& json, const ContactMethod* cm) -{ - //Check if the object is already loaded - QStringList sha1List; - QJsonArray as = json["sha1s"].toArray(); - for (int i = 0; i < as.size(); ++i) { - sha1List.append(as[i].toString()); - } - - if (sha1List.isEmpty()) - return nullptr; - - QByteArray sha1 = sha1List[0].toLatin1(); - - if (sha1List.size() > 1) { - sha1 = mashSha1s(sha1List); - } - - if (m_hPeers[sha1]) - return m_hPeers[sha1]; - - //Load from json - Serializable::Peers* p = new Serializable::Peers(); - p->read(json); - m_hPeers[sha1] = p; - - //TODO Remove in 2016 - //Some older versions of the file don't store necessary values, fix that - if (cm && p->peers.isEmpty()) - addPeer(p,cm); - - return p; -} - -media::TextRecordingPrivate::TextRecordingPrivate(TextRecording* r) : q_ptr(r),m_pImModel(nullptr),m_pCurrentGroup(nullptr),m_UnreadCount(0) -{ -} - -media::TextRecording::TextRecording() : Recording(Recording::Type::TEXT), d_ptr(new TextRecordingPrivate(this)) -{ -} - -media::TextRecording::~TextRecording() -{ - delete d_ptr; -} - -/** - * Updates the message status and potentially the message id, if a new status is set. - * Returns true if the Message object was modified, false otherwise. - */ -bool media::TextRecordingPrivate::updateMessageStatus(Serializable::Message* m, TextRecording::Status newSatus) -{ - bool modified = false; - - if (static_cast<int>(newSatus) >= static_cast<int>(TextRecording::Status::COUNT__)) { - qWarning() << "Unknown message status with code: " << static_cast<int>(newSatus); - newSatus = TextRecording::Status::UNKNOWN; - } else { - //READ status is not used yet it'll be the final state when it is - if (newSatus == TextRecording::Status::READ - || newSatus == TextRecording::Status::SENT - || newSatus == TextRecording::Status::FAILURE) { - m_hPendingMessages.remove(m->id); - if (m->id != 0) { - m->id = 0; - modified = true; - } - } - } - - if (m->deliveryStatus != newSatus) { - m->deliveryStatus = newSatus; - modified = true; - } - return modified; -} - -void media::TextRecordingPrivate::accountMessageStatusChanged(const uint64_t id, DRing::Account::MessageStates status) -{ - if (auto node = m_hPendingMessages.value(id, nullptr)) { - if (updateMessageStatus(node->m_pMessage, static_cast<TextRecording::Status>(status))) { - //You're looking at why local file storage is a "bad" idea - q_ptr->save(); - - auto msg_index = m_pImModel->index(node->m_row, 0); - m_pImModel->dataChanged(msg_index, msg_index); - } - } -} - -bool media::TextRecording::hasMimeType(const QString& mimeType) const -{ - return d_ptr->m_hMimeTypes.contains(mimeType); -} - -QStringList media::TextRecording::mimeTypes() const -{ - return d_ptr->m_lMimeTypes; -} - -///Get the instant messaging model associated with this recording -QAbstractItemModel* media::TextRecording::instantMessagingModel() const -{ - if (!d_ptr->m_pImModel) { - d_ptr->m_pImModel = new InstantMessagingModel(const_cast<TextRecording*>(this)); - } - - return d_ptr->m_pImModel; -} - -///Set all messages as read and then save the recording -void media::TextRecording::setAllRead() -{ - bool changed = false; - for(int row = 0; row < d_ptr->m_lNodes.size(); ++row) { - if (!d_ptr->m_lNodes[row]->m_pMessage->isRead) { - d_ptr->m_lNodes[row]->m_pMessage->isRead = true; - if (d_ptr->m_pImModel) { - auto idx = d_ptr->m_pImModel->index(row, 0); - emit d_ptr->m_pImModel->dataChanged(idx,idx); - } - changed = true; - } - } - if (changed) { - // TODO: we assume that the CM is the same for now, and that at least some of the messages - // are text - int oldVal = d_ptr->m_UnreadCount; - d_ptr->m_UnreadCount = 0; - emit unreadCountChange(-oldVal); - emit d_ptr->m_lNodes[0]->m_pContactMethod->unreadTextMessageCountChanged(); - emit d_ptr->m_lNodes[0]->m_pContactMethod->changed(); - save(); - } -} - -QVector<ContactMethod*> media::TextRecording::peers() const -{ - QVector<ContactMethod*> cms; - - for (const Serializable::Peers* peers : d_ptr->m_lAssociatedPeers) { - for (const Serializable::Peer* peer : peers->peers) { - cms << peer->m_pContactMethod; - } - } - - return cms; -} - -/** - * I (Emmanuel Lepage) is in the process of writing a better one for this that - * can be upstreamed into Qt (there is interest in merging a generic QVariant - filter model), however, it is too complex to merge into LRC for such basic - use case. So, for the sake of simplicity until upstream have this feature, - here is a subset of the generic filter proxy. The time between now and the - Qt review + Qt release + LRC drop old version of Qt is too long anyway. - - A copy of the code (copyrighted by me) is available in the ring-kde - next release for those interested. In 2016-2017, this code could probably - be replaced by the new one, be it in KItemModels (the KDE abstract proxy - library) or QtCore. - */ -class TextProxyModel : public QSortFilterProxyModel -{ -public: - explicit TextProxyModel(QObject* parent) : QSortFilterProxyModel(parent){} - virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override - { - const QModelIndex srcIdx = sourceModel()->index(source_row, filterKeyColumn(), source_parent); - - return srcIdx.data((int)media::TextRecording::Role::HasText).toBool(); - } -}; - -/** - * Subset of the instantMessagingModel() with only plain text and HTML - * messages. This model can be displayed directly to the user. - */ -QAbstractItemModel* media::TextRecording::instantTextMessagingModel() const -{ - if (!d_ptr->m_pTextMessagesModel) { - auto p = new TextProxyModel(const_cast<TextRecording*>(this)); - p->setSourceModel(instantMessagingModel()); - d_ptr->m_pTextMessagesModel = p; - } - - return d_ptr->m_pTextMessagesModel; -} - -/** - * Proxy model to get the unread text messages, as well as their number (rowCount) - */ -class UnreadProxyModel : public QSortFilterProxyModel -{ -public: - explicit UnreadProxyModel(QObject* parent) : QSortFilterProxyModel(parent){} - virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override - { - const QModelIndex srcIdx = sourceModel()->index(source_row, filterKeyColumn(), source_parent); - - return !srcIdx.data((int)media::TextRecording::Role::IsRead).toBool(); - } -}; - -/** - * Subset of the instantTextMessagingModel() with only unread plain text and HTML - * messages. This model can be used to get the number of unread messages. - */ -QAbstractItemModel* media::TextRecording::unreadInstantTextMessagingModel() const -{ - if (!d_ptr->m_pUnreadTextMessagesModel) { - auto p = new UnreadProxyModel(instantTextMessagingModel()); - p->setSourceModel(instantTextMessagingModel()); - d_ptr->m_pUnreadTextMessagesModel = p; - } - - return d_ptr->m_pUnreadTextMessagesModel; -} - - -bool media::TextRecording::isEmpty() const -{ - return !size(); -} - -int media::TextRecording::size() const -{ - return d_ptr->m_lNodes.size(); -} - -// Qt convention compat -int media::TextRecording::count() const { return size(); } - -QHash<QByteArray,QByteArray> media::TextRecordingPrivate::toJsons() const -{ - QHash<QByteArray,QByteArray> ret; - for (Serializable::Peers* p : m_lAssociatedPeers) { -// if (p->hasChanged) { - p->hasChanged = false; - - QJsonObject output; - p->write(output); - - QJsonDocument doc(output); - ret[p->sha1s[0].toLatin1()] = doc.toJson(); -// } - } - - return ret; -} - -media::TextRecording* media::TextRecording::fromJson(const QList<QJsonObject>& items, const ContactMethod* cm, CollectionInterface* backend) -{ - TextRecording* t = new TextRecording(); - if (backend) - t->setCollection(backend); - - ConfigurationManagerInterface& configurationManager = ConfigurationManager::instance(); - - //Load the history data - for (const QJsonObject& obj : items) { - Serializable::Peers* p = SerializableEntityManager::fromJson(obj,cm); - t->d_ptr->m_lAssociatedPeers << p; - } - - //Create the model - bool statusChanged = false; // if a msg status changed during parsing, we need to re-save the model - t->instantMessagingModel(); - - //Reconstruct the conversation - //TODO do it right, right now it flatten the graph - for (const Serializable::Peers* p : t->d_ptr->m_lAssociatedPeers) { - //Seems old version didn't store that - if (p->peers.isEmpty()) - continue; - // TODO: for now assume the convo is with only 1 CM at a time - auto peerCM = p->peers.at(0)->m_pContactMethod; - - // get the latest timestamp to set last used - time_t lastUsed = 0; - for (const Serializable::Group* g : p->groups) { - for (Serializable::Message* m : g->messages) { - ::TextMessageNode* n = new ::TextMessageNode(); - n->m_pMessage = m ; - if (!n->m_pMessage->contactMethod) { - if (cm) { - n->m_pMessage->contactMethod = const_cast<ContactMethod*>(cm); //TODO remove in 2016 - n->m_pMessage->authorSha1 = cm->sha1(); - - if (p->peers.isEmpty()) - addPeer(const_cast<Serializable::Peers*>(p), cm); - } else { - if (p->m_hSha1.contains(n->m_pMessage->authorSha1)) { - n->m_pMessage->contactMethod = p->m_hSha1[n->m_pMessage->authorSha1]; - } else { - // message was outgoing and author sha1 was set to that of the sending account - n->m_pMessage->contactMethod = peerCM; - n->m_pMessage->authorSha1 = peerCM->sha1(); - } - } - } - n->m_pContactMethod = m->contactMethod; - t->d_ptr->m_pImModel->addRowBegin(); - t->d_ptr->m_lNodes << n; - t->d_ptr->m_pImModel->addRowEnd(); - - if (lastUsed < n->m_pMessage->timestamp) - lastUsed = n->m_pMessage->timestamp; - if (m->id) { - int status = configurationManager.getMessageStatus(m->id); - t->d_ptr->m_hPendingMessages[m->id] = n; - if (t->d_ptr->updateMessageStatus(m, static_cast<TextRecording::Status>(status))) - statusChanged = true; - } - } - } - - if (statusChanged) - t->save(); - - // update the timestamp of the CM - peerCM->setLastUsed(lastUsed); - } - - return t; -} - -void media::TextRecordingPrivate::insertNewMessage(const QMap<QString,QString>& message, ContactMethod* cm, media::Media::Direction direction, uint64_t id) -{ - //Only create it if none was found on the disk - if (!m_pCurrentGroup) { - m_pCurrentGroup = new Serializable::Group(); - - auto cMethod = q_ptr->call() ? q_ptr->call()->peerContactMethod() : cm; - - Serializable::Peers* p = SerializableEntityManager::peer(cMethod); - - if (m_lAssociatedPeers.indexOf(p) == -1) { - m_lAssociatedPeers << p; - } - p->groups << m_pCurrentGroup; - } - - //Create the message - time_t currentTime; - ::time(¤tTime); - Serializable::Message* m = new Serializable::Message(); - - m->timestamp = currentTime ; - m->direction = direction ; - m->type = Serializable::Message::Type::CHAT; - m->authorSha1= cm->sha1() ; - m->id = id; - - if (direction == media::Media::Direction::OUT) - m->isRead = true; // assume outgoing messages are read, since we're sending them - - static const int profileSize = QString(RingMimes::PROFILE_VCF).size(); - - QMapIterator<QString, QString> iter(message); - while (iter.hasNext()) { - iter.next(); - if (iter.key().left(profileSize) == RingMimes::PROFILE_VCF) - return; - if (iter.value() != QLatin1String("application/resource-lists+xml")) { //This one is useless - const QString mimeType = iter.key(); - - Serializable::Payload* p = new Serializable::Payload(); - p->mimeType = mimeType ; - p->payload = iter.value(); - m->payloads << p; - - if (p->mimeType == QLatin1String("text/plain")) { - m->m_PlainText = p->payload; - m->m_HasText = true; - } - else if (p->mimeType == QLatin1String("text/html")) { - m->m_HTML = p->payload; - m->m_HasText = true; - } - - // Make the clients life easier and tell the payload type - const int hasArgs = mimeType.indexOf(';'); - const QString strippedMimeType = hasArgs != -1 ? mimeType.left(hasArgs) : mimeType; - const int currentSize = m_hMimeTypes.size(); - - m_hMimeTypes[strippedMimeType] = true; - - if (currentSize != m_hMimeTypes.size()) - m_lMimeTypes << strippedMimeType; - } - } - m_pCurrentGroup->messages << m; - - //Make sure the model exist - q_ptr->instantMessagingModel(); - - //Update the reconstructed conversation - ::TextMessageNode* n = new ::TextMessageNode() ; - n->m_pMessage = m ; - n->m_pContactMethod = const_cast<ContactMethod*>(cm); - n->m_row = m_pImModel->rowCount(); - m_pImModel->addRowBegin(); - m_lNodes << n; - m_pImModel->addRowEnd(); - - if (m->id > 0) - m_hPendingMessages[id] = n; - - //Save the conversation - q_ptr->save(); - - cm->setLastUsed(currentTime); - emit q_ptr->messageInserted(message, const_cast<ContactMethod*>(cm), direction); - if (!m->isRead) { - m_UnreadCount += 1; - emit q_ptr->unreadCountChange(1); - emit cm->unreadTextMessageCountChanged(); - emit cm->changed(); - } -} - -void Serializable::Payload::read(const QJsonObject &json) -{ - payload = json["payload" ].toString(); - mimeType = json["mimeType"].toString(); -} - -void Serializable::Payload::write(QJsonObject& json) const -{ - json["payload" ] = payload ; - json["mimeType"] = mimeType; -} - -void Serializable::Message::read (const QJsonObject &json) -{ - timestamp = json["timestamp" ].toInt ( ); - authorSha1 = json["authorSha1"].toString ( ); - isRead = json["isRead" ].toBool ( ); - direction = static_cast<media::Media::Direction> ( json["direction"].toInt() ); - type = static_cast<Serializable::Message::Type>( json["type" ].toInt() ); - id = json["id" ].toVariant().value<uint64_t>( ); - deliveryStatus = static_cast<media::TextRecording::Status>(json["deliveryStatus"].toInt()); - - QJsonArray a = json["payloads"].toArray(); - for (int i = 0; i < a.size(); ++i) { - QJsonObject o = a[i].toObject(); - Payload* p = new Payload(); - p->read(o); - payloads << p; - - if (p->mimeType == "text/plain") { - m_PlainText = p->payload; - m_HasText = true; - } - else if (p->mimeType == "text/html") { - m_HTML = p->payload; - m_HasText = true; - } - } - - //Load older conversation from a time when only 1 mime/payload pair was supported - if (!json["payload" ].toString().isEmpty()) { - Payload* p = new Payload(); - p->payload = json["payload" ].toString(); - p->mimeType = json["mimeType" ].toString(); - payloads << p; - m_PlainText = p->payload; - m_HasText = true; - } -} - -void Serializable::Message::write(QJsonObject &json) const -{ - json["timestamp" ] = static_cast<int>(timestamp); - json["authorSha1" ] = authorSha1 ; - json["direction" ] = static_cast<int>(direction); - json["type" ] = static_cast<int>(type) ; - json["isRead" ] = isRead ; - json["id" ] = QString::number(id); - json["deliveryStatus" ] = static_cast<int>(deliveryStatus); - - QJsonArray a; - foreach (const Payload* p, payloads) { - QJsonObject o; - p->write(o); - a.append(o); - } - json["payloads"] = a; -} - -const QRegularExpression Serializable::Message::m_linkRegex = QRegularExpression(QStringLiteral("((?>(?>https|http|ftp|ring):|www\\.)(?>[^\\s,.);!>]|[,.);!>](?!\\s|$))+)"), - QRegularExpression::CaseInsensitiveOption); - -const QString& Serializable::Message::getFormattedHtml() -{ - if (m_FormattedHtml.isEmpty()) - { - QString re; - auto p = 0; - auto it = m_linkRegex.globalMatch(m_PlainText); - while (it.hasNext()) { - QRegularExpressionMatch match = it.next(); - auto start = match.capturedStart(); - - auto url = QUrl::fromUserInput(match.capturedRef().toString()); - - if (start > p) - re.append(m_PlainText.mid(p, start - p).toHtmlEscaped().replace(QLatin1Char('\n'), - QStringLiteral("<br/>"))); - re.append(QStringLiteral("<a href=\"%1\">%2</a>") - .arg(QString::fromLatin1(url.toEncoded()).toHtmlEscaped(), - match.capturedRef().toString().toHtmlEscaped())); - m_LinkList.append(url); - p = match.capturedEnd(); - } - if (p < m_PlainText.size()) - re.append(m_PlainText.mid(p, m_PlainText.size() - p).toHtmlEscaped()); - - m_FormattedHtml = QString("<body>%1</body>").arg(re); - } - return m_FormattedHtml; -} - -void Serializable::Group::read (const QJsonObject &json, const QHash<QString,ContactMethod*> sha1s) -{ - id = json["id" ].toInt (); - nextGroupSha1 = json["nextGroupSha1"].toString(); - nextGroupId = json["nextGroupId" ].toInt (); - - QJsonArray a = json["messages"].toArray(); - for (int i = 0; i < a.size(); ++i) { - QJsonObject o = a[i].toObject(); - Message* message = new Message(); - message->contactMethod = sha1s[message->authorSha1]; - message->read(o); - messages.append(message); - } -} - -void Serializable::Group::write(QJsonObject &json) const -{ - json["id" ] = id ; - json["nextGroupSha1" ] = nextGroupSha1; - json["nextGroupId" ] = nextGroupId ; - - QJsonArray a; - for (const Message* m : messages) { - QJsonObject o; - m->write(o); - a.append(o); - } - json["messages"] = a; -} - -void Serializable::Peer::read (const QJsonObject &json) -{ - accountId = json["accountId"].toString(); - uri = json["uri" ].toString(); - personUID = json["personUID"].toString(); - sha1 = json["sha1" ].toString(); - - Account* a = AccountModel::instance().getById(accountId.toLatin1()); - Person* person = personUID.isEmpty() ? - nullptr : PersonModel::instance().getPersonByUid(personUID.toLatin1()); - - m_pContactMethod = PhoneDirectoryModel::instance().getNumber(uri,person,a); -} - -void Serializable::Peer::write(QJsonObject &json) const -{ - json["accountId"] = accountId ; - json["uri" ] = uri ; - json["personUID"] = personUID ; - json["sha1" ] = sha1 ; -} - -void Serializable::Peers::read (const QJsonObject &json) -{ - - QJsonArray as = json["sha1s"].toArray(); - for (int i = 0; i < as.size(); ++i) { - sha1s.append(as[i].toString()); - } - - QJsonArray a2 = json["peers"].toArray(); - for (int i = 0; i < a2.size(); ++i) { - QJsonObject o = a2[i].toObject(); - Peer* peer = new Peer(); - peer->read(o); - m_hSha1[peer->sha1] = peer->m_pContactMethod; - peers.append(peer); - } - - QJsonArray a = json["groups"].toArray(); - for (int i = 0; i < a.size(); ++i) { - QJsonObject o = a[i].toObject(); - Group* group = new Group(); - group->read(o,m_hSha1); - groups.append(group); - } -} - -void Serializable::Peers::write(QJsonObject &json) const -{ - QJsonArray a2; - for (const QString& sha1 : sha1s) { - a2.append(sha1); - } - json["sha1s"] = a2; - - QJsonArray a; - for (const Group* g : groups) { - QJsonObject o; - g->write(o); - a.append(o); - } - json["groups"] = a; - - QJsonArray a3; - for (const Peer* p : peers) { - QJsonObject o; - p->write(o); - a3.append(o); - } - json["peers"] = a3; -} - - -///Constructor -InstantMessagingModel::InstantMessagingModel(media::TextRecording* recording) : QAbstractListModel(recording),m_pRecording(recording) -{ -} - -InstantMessagingModel::~InstantMessagingModel() -{ -// delete d_ptr; -} - -QHash<int,QByteArray> InstantMessagingModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles.insert((int)media::TextRecording::Role::Direction , "direction" ); - roles.insert((int)media::TextRecording::Role::AuthorDisplayname , "authorDisplayname" ); - roles.insert((int)media::TextRecording::Role::AuthorUri , "authorUri" ); - roles.insert((int)media::TextRecording::Role::AuthorPresenceStatus, "authorPresenceStatus"); - roles.insert((int)media::TextRecording::Role::Timestamp , "timestamp" ); - roles.insert((int)media::TextRecording::Role::IsRead , "isRead" ); - roles.insert((int)media::TextRecording::Role::FormattedDate , "formattedDate" ); - roles.insert((int)media::TextRecording::Role::IsStatus , "isStatus" ); - roles.insert((int)media::TextRecording::Role::DeliveryStatus , "deliveryStatus" ); - roles.insert((int)media::TextRecording::Role::FormattedHtml , "formattedHtml" ); - roles.insert((int)media::TextRecording::Role::LinkList , "linkList" ); - roles.insert((int)media::TextRecording::Role::Id , "id" ); - } - return roles; -} - -///Get data from the model -QVariant InstantMessagingModel::data( const QModelIndex& idx, int role) const -{ - if (idx.column() == 0) { - ::TextMessageNode* n = m_pRecording->d_ptr->m_lNodes[idx.row()]; - switch (role) { - case Qt::DisplayRole: - return QVariant(n->m_pMessage->m_PlainText); - case Qt::DecorationRole : - if (n->m_pMessage->direction == media::Media::Direction::IN) - return GlobalInstances::pixmapManipulator().decorationRole(n->m_pContactMethod); - else if (m_pRecording->call() && m_pRecording->call()->account() - && m_pRecording->call()->account()->contactMethod()->contact()) { - auto cm = m_pRecording->call()->account()->contactMethod(); - return GlobalInstances::pixmapManipulator().decorationRole(cm); - } else if (n->m_pMessage->direction == media::Media::Direction::OUT && n->m_pContactMethod->account()){ - return GlobalInstances::pixmapManipulator().decorationRole(n->m_pContactMethod->account()); - } else { - /* It's most likely an account that doesn't exist anymore - * Use a fallback image in pixmapManipulator - */ - return GlobalInstances::pixmapManipulator().decorationRole((ContactMethod*)nullptr); - } - break; - case (int)media::TextRecording::Role::Direction : - return QVariant::fromValue(n->m_pMessage->direction); - case (int)media::TextRecording::Role::AuthorDisplayname : - case (int)Ring::Role::Name : - if (n->m_pMessage->direction == media::Media::Direction::IN) - return n->m_pContactMethod->roleData(static_cast<int>(Ring::Role::Name)); - else - return tr("Me"); - case (int)media::TextRecording::Role::AuthorUri : - case (int)Ring::Role::Number : - return n->m_pContactMethod->uri(); - case (int)media::TextRecording::Role::AuthorPresenceStatus : - // Always consider "self" as present - if (n->m_pMessage->direction == media::Media::Direction::OUT) - return true; - else - return n->m_pContactMethod->contact() ? - n->m_pContactMethod->contact()->isPresent() : n->m_pContactMethod->isPresent(); - case (int)media::TextRecording::Role::Timestamp : - return (uint)n->m_pMessage->timestamp; - case (int)media::TextRecording::Role::IsRead : - return (int)n->m_pMessage->isRead; - case (int)media::TextRecording::Role::FormattedDate : - return QDateTime::fromTime_t(n->m_pMessage->timestamp).toString(); - case (int)media::TextRecording::Role::IsStatus : - return n->m_pMessage->type == Serializable::Message::Type::STATUS; - case (int)media::TextRecording::Role::HTML : - return QVariant(n->m_pMessage->m_HTML); - case (int)media::TextRecording::Role::HasText : - return n->m_pMessage->m_HasText; - case (int)media::TextRecording::Role::ContactMethod : - return QVariant::fromValue(n->m_pContactMethod); - case (int)media::TextRecording::Role::DeliveryStatus : - return QVariant::fromValue(n->m_pMessage->deliveryStatus); - case (int)media::TextRecording::Role::FormattedHtml : - return QVariant::fromValue(n->m_pMessage->getFormattedHtml()); - case (int)media::TextRecording::Role::LinkList : - return QVariant::fromValue(n->m_pMessage->m_LinkList); - case (int)media::TextRecording::Role::Id : - return QVariant::fromValue(n->m_pMessage->id); - default: - break; - } - } - return QVariant(); -} - -///Number of row -int InstantMessagingModel::rowCount(const QModelIndex& parentIdx) const -{ - if (!parentIdx.isValid()) - return m_pRecording->d_ptr->m_lNodes.size(); - return 0; -} - -///Model flags -Qt::ItemFlags InstantMessagingModel::flags(const QModelIndex& idx) const -{ - Q_UNUSED(idx) - return Qt::ItemIsEnabled; -} - -///Set model data -bool InstantMessagingModel::setData(const QModelIndex& idx, const QVariant &value, int role) -{ - if (idx.column() || !idx.isValid()) - return false; - - bool changed = false; - - ::TextMessageNode* n = m_pRecording->d_ptr->m_lNodes[idx.row()]; - switch (role) { - case (int)media::TextRecording::Role::IsRead : - if (n->m_pMessage->isRead != value.toBool()) { - n->m_pMessage->isRead = value.toBool(); - if (n->m_pMessage->m_HasText) { - int val = value.toBool() ? -1 : +1; - m_pRecording->d_ptr->m_UnreadCount += val; - emit m_pRecording->unreadCountChange(val); - emit n->m_pContactMethod->unreadTextMessageCountChanged(); - emit n->m_pContactMethod->changed(); - } - emit dataChanged(idx,idx); - changed = true; - } - break; - default: - return false; - } - - //Save the conversation - if (changed) - m_pRecording->save(); - return true; -} - -void InstantMessagingModel::addRowBegin() -{ - const int rc = rowCount(); - beginInsertRows(QModelIndex(),rc,rc); -} - -void InstantMessagingModel::addRowEnd() -{ - endInsertRows(); -} - -void media::TextRecordingPrivate::clear() -{ - m_pImModel->clear(); - - if (m_UnreadCount != 0) { - m_UnreadCount = 0; - emit q_ptr->unreadCountChange(0); - } -} - -void InstantMessagingModel::clear() -{ - beginResetModel(); - - for ( TextMessageNode *node : m_pRecording->d_ptr->m_lNodes) { - for (Serializable::Payload *payload : node->m_pMessage->payloads) { - delete payload; - } - delete node->m_pMessage; - delete node; - } - m_pRecording->d_ptr->m_lNodes.clear(); - - for (Serializable::Peers *peers : m_pRecording->d_ptr->m_lAssociatedPeers) { - for (Serializable::Group *group : peers->groups) { - group->messages.clear(); - } - } - m_pRecording->d_ptr->m_lAssociatedPeers.clear(); - - //TODO: holly memory leaks batman! what else do we need to delete? - - m_pRecording->d_ptr->m_pCurrentGroup = nullptr; - m_pRecording->d_ptr->m_hMimeTypes.clear(); - m_pRecording->d_ptr->m_lMimeTypes.clear(); - - endResetModel(); -} diff --git a/src/media/textrecording.h b/src/media/textrecording.h deleted file mode 100644 index e60b938c8e6f6209fc5ea0b9d2901800a6664db0..0000000000000000000000000000000000000000 --- a/src/media/textrecording.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "media/recording.h" -#include "media/media.h" -#include "itemdataroles.h" - -//Qt -class QJsonObject; -class QAbstractItemModel; - -//Ring -class IMConversationManagerPrivate; -class LocalTextRecordingEditor; -class ContactMethod; -class InstantMessagingModel; - -namespace media { - -class TextRecordingPrivate; -class Text; - -class LIB_EXPORT TextRecording : public Recording -{ - Q_OBJECT - - //InstantMessagingModel is a view on top of TextRecording data - friend class ::InstantMessagingModel; - friend class ::IMConversationManagerPrivate; - friend class ::LocalTextRecordingEditor; - friend class Text; - friend class ::ContactMethod; - -public: - - enum class Role { - Direction = static_cast<int>(Ring::Role::UserRole) + 1, - AuthorDisplayname , - AuthorUri , - AuthorPresenceStatus , - Timestamp , - IsRead , - FormattedDate , - IsStatus , - HTML , - HasText , - ContactMethod , - DeliveryStatus , - FormattedHtml , - LinkList , - Id , - }; - - ///Possible messages states - ///Order is important and reflected on order in Daemon - enum class Status : unsigned int{ - UNKNOWN = 0, - SENDING, - SENT, - READ, - FAILURE, - COUNT__, - }; - Q_ENUMS(Status) - - //Constructor - explicit TextRecording(); - virtual ~TextRecording(); - static TextRecording* fromJson(const QList<QJsonObject>& items, const ContactMethod* cm = nullptr, CollectionInterface* backend = nullptr); - - //Getter - QAbstractItemModel* instantMessagingModel ( ) const; - QAbstractItemModel* instantTextMessagingModel( ) const; - QAbstractItemModel* unreadInstantTextMessagingModel( ) const; - bool isEmpty ( ) const; - int count ( ) const; - int size ( ) const; - bool hasMimeType ( const QString& mimeType ) const; - QStringList mimeTypes ( ) const; - QVector<ContactMethod*> peers ( ) const; - - //Helper - void setAllRead(); - -Q_SIGNALS: - void messageInserted(const QMap<QString,QString>& message, ContactMethod* cm, media::Media::Direction direction); - void unreadCountChange(int count); - -private: - TextRecordingPrivate* d_ptr; - Q_DECLARE_PRIVATE(TextRecording) -}; - -} - -Q_DECLARE_METATYPE(media::TextRecording::Status) diff --git a/src/media/video.cpp b/src/media/video.cpp deleted file mode 100644 index 6ef436a2c579d547fd4b57f2029929cfcda4b711..0000000000000000000000000000000000000000 --- a/src/media/video.cpp +++ /dev/null @@ -1,68 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "video.h" - -//Dring -#include <media_const.h> -#include <video/sourcemodel.h> -#include "dbus/callmanager.h" - -//Ring -#include <call.h> - -class MediaVideoPrivate -{ -public: - Video::SourceModel *m_pSourceModel = nullptr; -}; - -media::Video::Video(Call* parent, const Media::Direction direction) : media::Media(parent, direction), d_ptr(new MediaVideoPrivate()) -{ - Q_ASSERT(parent); -} - -media::Media::Type media::Video::type() -{ - return media::Media::Type::VIDEO; -} - -bool media::Video::mute() -{ - CallManagerInterface& callManager = CallManager::instance(); - return callManager.muteLocalMedia(call()->dringId(),DRing::Media::Details::MEDIA_TYPE_VIDEO,true); -} - -bool media::Video::unmute() -{ - CallManagerInterface& callManager = CallManager::instance(); - return callManager.muteLocalMedia(call()->dringId(),DRing::Media::Details::MEDIA_TYPE_VIDEO,false); -} - -Video::SourceModel* media::Video::sourceModel() const -{ - if (!d_ptr->m_pSourceModel) { - d_ptr->m_pSourceModel = new ::Video::SourceModel(); - } - - return d_ptr->m_pSourceModel; -} - -media::Video::~Video() -{ - delete d_ptr; -} diff --git a/src/media/video.h b/src/media/video.h deleted file mode 100644 index 4c7f1f814abd16105c0a747b0bdf73f5c447fc87..0000000000000000000000000000000000000000 --- a/src/media/video.h +++ /dev/null @@ -1,52 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <media/media.h> -#include <typedefs.h> - -namespace Video{ -class SourceModel; -} - - -class MediaVideoPrivate; -class Call; -class CallPrivate; - -namespace media { - -class LIB_EXPORT Video : public media::Media -{ - friend class ::CallPrivate; -public: - - virtual Media::Type type() override; - virtual bool mute() override; - virtual bool unmute() override; - ::Video::SourceModel* sourceModel() const; - -private: - Video(Call* parent, const Media::Direction direction); - virtual ~Video(); - - MediaVideoPrivate* d_ptr; -}; - -} - diff --git a/src/mime.cpp b/src/mime.cpp deleted file mode 100644 index 0ab21458a821acbee770fb5ea48c432395c2c665..0000000000000000000000000000000000000000 --- a/src/mime.cpp +++ /dev/null @@ -1,169 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "mime.h" - -//Qt -#include <QtCore/QMimeData> -#include <QtCore/QTextStream> -#include <QtCore/QDateTime> - -//LRC -#include <call.h> -#include <person.h> -#include <contactmethod.h> -#include <numbercategory.h> - -/** - * This method enable inter-operability with various third party applications - * by converting Ring objects into various standard MIME representations. - * - * This is designed to be an unified algorithm for drag and drop and copy and - * paste. It replace no less than 17 chunks of code (LRC + KDE client) that - * either all did the same thing or were missing parts. - * - * This methods need to be accessed directly in same specific scenarios, - * otherwise, helper methods "mimePayload() const" are available for - * Call, Person and ContactMethod. - * - * @note If new MIME are ever to be supported, this algorithm has to be - * updated instead of hardcoding the payload in a random file. - */ -QMimeData* RingMimes::payload(const Call* c, const ContactMethod* cm, const Person* p) -{ - if (!c && !cm && !p) - return nullptr; - - // Deduce other objects where applicable - if (c && !cm) - cm = c->peerContactMethod(); - - if (!cm && p && p->phoneNumbers().size() == 1) - cm = p->phoneNumbers().first(); - - if (!p && cm->contact()) - p = cm->contact(); - - QMimeData* d = new QMimeData(); - - // Person - if (p) { - - // Ring interface contact identifier - d->setData(RingMimes::CONTACT, p->uid()); - - // Serialise as vCard for PIM applications - const QByteArray vcf = p->toVCard(); - - // A quick search and tests show those are common vard MIMEs - d->setData(RingMimes::VCF , vcf ); - d->setData(RingMimes::XVCF , vcf ); - d->setData(RingMimes::MAC_VCF, vcf ); - - } - - // URI list for other soft phones are SIP aware applications - if (cm) { - - // This is the format used by URI list I found - d->setData(RingMimes::URI_LIST, cm->uri().full().toUtf8()); - - } - else if (p) { - QString uriList; - QTextStream stream(&uriList); - - foreach (const ContactMethod* number, p->phoneNumbers()) { - stream << number->uri().format( - URI::Section::SCHEME | - URI::Section::USER_INFO | - URI::Section::HOSTNAME | - URI::Section::PORT - ) << QChar('\n'); - } - - d->setData(RingMimes::URI_LIST, uriList.toUtf8()); - } - - // Allow conference and transfer by drag and drop - if (c) { - - if (c->type() == Call::Type::CALL && c->hasRemote()) - d->setData(RingMimes::CALLID , c->dringId().toLatin1() ); - else if (c->type() == Call::Type::HISTORY) - d->setData(RingMimes::HISTORYID, c->dringId().toLatin1() ); - - if (cm) - d->setData(RingMimes::PHONENUMBER, cm->toHash().toUtf8()); - - } - - // The "default" plain text and HTML representation - if (c) { - - // The photo could be embdeed in the HTML as BASE64 JPG - d->setData(RingMimes::HTML_TEXT , QString( - "<p>\n" - " <b>%1</b><br />\n" /* Name */ - " %2<br />\n" /* URI */ - " <i>%3</i><br />\n" /* Time */ - "</p>" - ) - .arg( c->formattedName() ) - .arg( cm->uri() ) - .arg( QDateTime::fromTime_t(c->startTimeStamp()).toString() ) - .toUtf8() - ); - - d->setData(RingMimes::PLAIN_TEXT, QString("%1\n%2\n%3\n") - .arg( c->formattedName() ) - .arg( c->peerContactMethod()->uri() ) - .arg( QDateTime::fromTime_t(c->startTimeStamp()).toString() ) - .toUtf8() ); - - } - else if (cm) { - d->setData(RingMimes::PLAIN_TEXT, cm->uri().toUtf8() ); - } - else if (p) { - QString html , text; - QTextStream htmlStream(&html), textStream(&text); - - // Contact name - htmlStream << QString("<p>\n" - " <b>%1</b><br />\n").arg(p->formattedName()); - - // Phone numbers (as saved in the contacts) - foreach (const ContactMethod* number, p->phoneNumbers()) { - - htmlStream << number->uri() - << QStringLiteral(" (") - << number->category()->name() - << QStringLiteral(") <br />\n"); - - textStream << number->uri() << QChar('\n'); - } - - htmlStream << QStringLiteral("</p>"); - - d->setData(RingMimes::PLAIN_TEXT, text.toUtf8() ); - d->setData(RingMimes::HTML_TEXT , html.toUtf8() ); - - } - - return d; -} diff --git a/src/mime.h b/src/mime.h deleted file mode 100644 index ddb7a55dada0016b4bc187b861bbfd44cb057a5f..0000000000000000000000000000000000000000 --- a/src/mime.h +++ /dev/null @@ -1,47 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -// Qt -class QMimeData; - -// LRC -class Call; -class ContactMethod; -class Person; - -namespace RingMimes { - //TODO use QStringLiteral - constexpr static const char* CALLID = "text/ring.call.id" ; - constexpr static const char* CONTACT = "text/ring.contact" ; - constexpr static const char* HISTORYID = "text/ring.history.id" ; - constexpr static const char* PHONENUMBER = "text/ring.phone.number" ; - constexpr static const char* PLAIN_TEXT = "text/plain" ; - constexpr static const char* HTML_TEXT = "text/html" ; - constexpr static const char* PROFILE = "text/ring.profile.id" ; - constexpr static const char* ACCOUNT = "text/sflphone.account.id" ; - constexpr static const char* AUDIO_CODEC = "text/ring.codec.audio" ; - constexpr static const char* VIDEO_CODEC = "text/ring.codec.video" ; - constexpr static const char* PROFILE_VCF = "x-ring/ring.profile.vcard"; - constexpr static const char* VCF = "text/vcard" ; - constexpr static const char* XVCF = "text/x-vcard" ; - constexpr static const char* MAC_VCF = "application/vcard" ; - constexpr static const char* URI_LIST = "text/uri-list" ; - - QMimeData* payload(const Call* c, const ContactMethod* cm, const Person* p); -} diff --git a/src/namedirectory.cpp b/src/namedirectory.cpp index 68ce5c978f8009a166bfe4d081b2a3ec186fef76..5dc2273ad2146ad4b56565f33ae782aaf84ec4dd 100644 --- a/src/namedirectory.cpp +++ b/src/namedirectory.cpp @@ -16,8 +16,9 @@ * along with this program. If not, see <http://www.gnu.org/licenses/>. * ***************************************************************************/ +#include <QCoreApplication> + #include "namedirectory.h" -#include "accountmodel.h" #include "private/namedirectory_p.h" #include "dbus/configurationmanager.h" @@ -47,16 +48,7 @@ void NameDirectoryPrivate::slotNameRegistrationEnded(const QString& accountId, i { qDebug() << "Name registration ended. Account:" << accountId << "status:" << status << "name:" << name; - Account* account = AccountModel::instance().getById(accountId.toLatin1()); - - emit q_ptr->nameRegistrationEnded(account, static_cast<NameDirectory::RegisterNameStatus>(status), name); - - if (account) { - emit account->nameRegistrationEnded(static_cast<NameDirectory::RegisterNameStatus>(status), name); - } - else { - qWarning() << "name registration ended for unknown account" << accountId; - } + emit q_ptr->nameRegistrationEnded(static_cast<NameDirectory::RegisterNameStatus>(status), name); } //Registered Name found @@ -76,37 +68,19 @@ void NameDirectoryPrivate::slotRegisteredNameFound(const QString& accountId, int break; } - Account* account = AccountModel::instance().getById(accountId.toLatin1()); - - emit q_ptr->registeredNameFound(account, static_cast<NameDirectory::LookupStatus>(status), address, name); - - if (account) { - emit account->registeredNameFound(static_cast<NameDirectory::LookupStatus>(status), address, name); - } - else { - qWarning() << "registered name found for unknown account" << accountId; - } -} - -//Register a name -bool NameDirectory::registerName(const Account* account, const QString& password, const QString& name) const -{ - QString accountId = account ? account->id() : QString(); - return ConfigurationManager::instance().registerName(accountId, password, name); + emit q_ptr->registeredNameFound( static_cast<NameDirectory::LookupStatus>(status), address, name); } //Lookup a name -bool NameDirectory::lookupName(const Account* account, const QString& nameServiceURL, const QString& name) const +bool NameDirectory::lookupName(const QString& nameServiceURL, const QString& name) const { - QString accountId = account ? account->id() : QString(); - return ConfigurationManager::instance().lookupName(accountId, nameServiceURL, name); + return ConfigurationManager::instance().lookupName("", nameServiceURL, name); } //Lookup an address -bool NameDirectory::lookupAddress(const Account* account, const QString& nameServiceURL, const QString& address) const +bool NameDirectory::lookupAddress(const QString& nameServiceURL, const QString& address) const { - QString accountId = account ? account->id() : QString(); - return ConfigurationManager::instance().lookupAddress(accountId, nameServiceURL, address); + return ConfigurationManager::instance().lookupAddress("", nameServiceURL, address); } NameDirectory::~NameDirectory() diff --git a/src/namedirectory.h b/src/namedirectory.h index 8d47c7b95e71e68905f5f9b80654fa5763f47808..3b7c1dfd9bf2fe01dc27d8ab477dc0bf43854d96 100644 --- a/src/namedirectory.h +++ b/src/namedirectory.h @@ -51,9 +51,8 @@ public: static NameDirectory& instance(); //Lookup - Q_INVOKABLE bool lookupName (const Account* account, const QString& nameServiceURL, const QString& name ) const; - Q_INVOKABLE bool lookupAddress (const Account* account, const QString& nameServiceURL, const QString& address ) const; - Q_INVOKABLE bool registerName (const Account* account, const QString& password, const QString& name ) const; + Q_INVOKABLE bool lookupName (const QString& nameServiceURL, const QString& name ) const; + Q_INVOKABLE bool lookupAddress (const QString& nameServiceURL, const QString& address ) const; private: //Constructors & Destructors @@ -66,10 +65,10 @@ private: Q_SIGNALS: ///RegisterName has ended - void nameRegistrationEnded(const Account* account, NameDirectory::RegisterNameStatus status, const QString& name); + void nameRegistrationEnded(NameDirectory::RegisterNameStatus status, const QString& name); ///Name or address lookup has completed - void registeredNameFound(Account* account, NameDirectory::LookupStatus status, const QString& address, const QString& name); + void registeredNameFound(NameDirectory::LookupStatus status, const QString& address, const QString& name); }; Q_DECLARE_METATYPE(NameDirectory*) diff --git a/src/newaccountmodel.cpp b/src/newaccountmodel.cpp index 4b508f917f7ff95472c32476668e004d585ef852..242c507f171af199e7cad0026acf33d2f35e6f50 100644 --- a/src/newaccountmodel.cpp +++ b/src/newaccountmodel.cpp @@ -42,7 +42,6 @@ #include "vcard.h" // old LRC -#include "accountmodel.h" #include "api/profile.h" #include "qtwrapper/conversions_wrap.hpp" diff --git a/src/newcallmodel.cpp b/src/newcallmodel.cpp index 92a8dd35ac428cf8b716d3225d143034d6e9f583..dc94bf54b7d5e5afabba59fa89b653b14b1651d0 100644 --- a/src/newcallmodel.cpp +++ b/src/newcallmodel.cpp @@ -30,8 +30,7 @@ #include "api/contactmodel.h" #include "api/newaccountmodel.h" #include "dbus/callmanager.h" -#include "mime.h" -#include "private/videorenderermanager.h" +#include "vcard.h" #include "video/renderer.h" // Ring daemon @@ -152,12 +151,6 @@ public Q_SLOTS: * @param code unused */ void slotCallStateChanged(const std::string& callId, const std::string &state, int code); - /** - * Listen from VideoRendererManager when a Renderer starts - * @param callId - * @param renderer - */ - void slotRemotePreviewStarted(const std::string& callId, Video::Renderer* renderer); /** * Listen from CallbacksHandler when a VCard chunk is incoming * @param callId @@ -392,16 +385,6 @@ NewCallModel::removeParticipant(const std::string& callId, const std::string& pa qDebug() << "removeParticipant() isn't implemented yet"; } -Video::Renderer* -NewCallModel::getRenderer(const std::string& callId) const -{ - #ifdef ENABLE_VIDEO - return VideoRendererManager::instance().getRenderer(callId); - #else - return nullptr; - #endif -} - std::string NewCallModel::getFormattedCallDuration(const std::string& callId) const { @@ -452,7 +435,6 @@ NewCallModelPimpl::NewCallModelPimpl(const NewCallModel& linked, const Callbacks { connect(&callbacksHandler, &CallbacksHandler::incomingCall, this, &NewCallModelPimpl::slotIncomingCall); connect(&callbacksHandler, &CallbacksHandler::callStateChanged, this, &NewCallModelPimpl::slotCallStateChanged); - connect(&VideoRendererManager::instance(), &VideoRendererManager::remotePreviewStarted, this, &NewCallModelPimpl::slotRemotePreviewStarted); connect(&callbacksHandler, &CallbacksHandler::incomingVCardChunk, this, &NewCallModelPimpl::slotincomingVCardChunk); connect(&callbacksHandler, &CallbacksHandler::conferenceCreated, this , &NewCallModelPimpl::slotConferenceCreated); @@ -618,12 +600,6 @@ NewCallModelPimpl::slotCallStateChanged(const std::string& callId, const std::st } } -void -NewCallModelPimpl::slotRemotePreviewStarted(const std::string& callId, Video::Renderer* renderer) -{ - emit linked.remotePreviewStarted(callId, renderer); -} - void NewCallModelPimpl::slotincomingVCardChunk(const std::string& callId, const std::string& from, @@ -702,7 +678,7 @@ NewCallModelPimpl::sendProfile(const std::string& callId) auto sizeLimit = std::min(1000, static_cast<int>(vCard.size())); MapStringString chunk; chunk[QString("%1; id=%2,part=%3,of=%4") - .arg( RingMimes::PROFILE_VCF ) + .arg( lrc::vCard::PROFILE_VCF ) .arg( key.c_str() ) .arg( QString::number( i+1 ) ) .arg( QString::number( total ) ) diff --git a/src/newvideo.cpp b/src/newvideo.cpp index c7abbca5c3b24cbab70072f776a3a54cc38a51a5..05869fe622766f54b83510b9a1aded5008c8fd74 100644 --- a/src/newvideo.cpp +++ b/src/newvideo.cpp @@ -28,6 +28,9 @@ // std #include <mutex> +// Qt +#include <QSize> + namespace lrc { diff --git a/src/numbercategory.cpp b/src/numbercategory.cpp deleted file mode 100644 index 5694f9a376c7bcb5910a2c6e53a8be71782d7ce4..0000000000000000000000000000000000000000 --- a/src/numbercategory.cpp +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "numbercategory.h" - -#include <QtCore/QSize> - -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "collectionmediator.h" -#include "collectioneditor.h" -#include "contactmethod.h" -#include "numbercategorymodel.h" -#include "private/numbercategorymodel_p.h" - -class NumberCategoryPrivate -{ -public: - NumberCategoryPrivate(); - - //Attributes - QString m_Name ; - QVariant m_pIcon; - int m_Key ; -}; - -NumberCategoryPrivate::NumberCategoryPrivate() : m_pIcon(), m_Name(), m_Key(-1) -{ -} - -NumberCategory::NumberCategory(CollectionMediator<ContactMethod>* mediator, const QString& name) : CollectionInterface(static_cast<CollectionEditor<ContactMethod>*>(nullptr)), d_ptr(new NumberCategoryPrivate()) -{ - Q_UNUSED(mediator) - d_ptr->m_Name = name; -} - -NumberCategory::~NumberCategory() -{ -} - -QVariant NumberCategory::icon() const -{ - return GlobalInstances::pixmapManipulator().numberCategoryIcon(d_ptr->m_pIcon,QSize(),false,false); -} - -QVariant NumberCategory::icon(bool isTracked, bool isPresent) const -{ - return GlobalInstances::pixmapManipulator().numberCategoryIcon(d_ptr->m_pIcon,QSize(),isTracked,isPresent); -} - -QString NumberCategory::name() const -{ - return d_ptr->m_Name; -} - -QString NumberCategory::category() const -{ - return QObject::tr("Phone number types"); -} - -bool NumberCategory::isEnabled() const -{ - return true; -} - -QByteArray NumberCategory::id() const -{ - return "numbercat"+d_ptr->m_Name.toLatin1(); -} - -bool NumberCategory::load() -{ - return false; -} - -int NumberCategory::size() const -{ - return NumberCategoryModel::instance().d_ptr->getSize(this); -} - -int NumberCategory::key() const -{ - return d_ptr->m_Key; -} - -FlagPack<CollectionInterface::SupportedFeatures> NumberCategory::supportedFeatures() const -{ - return CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::MANAGEABLE | - CollectionInterface::SupportedFeatures::LOAD ; -} - -void NumberCategory::setIcon(const QVariant& pixmap) -{ - d_ptr->m_pIcon = pixmap; -} - -void NumberCategory::setName(const QString& name) -{ - d_ptr->m_Name = name; -} - -void NumberCategory::setKey(const int key) -{ - d_ptr->m_Key = key; -} diff --git a/src/numbercategory.h b/src/numbercategory.h deleted file mode 100644 index e2ecebc79f11f87919dfebda2fd363ccfd898ca6..0000000000000000000000000000000000000000 --- a/src/numbercategory.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <collectioninterface.h> - -#include "typedefs.h" - -class QPixmap; -class NumberCategoryPrivate; -class ContactMethod; -class NumberCategoryModel; -template <typename T> class CollectionManagerInterface; - -/** - * This class represent a ContactMethod category. Categories usually - * come from the contact provider, but can be added dynamically too - */ -class LIB_EXPORT NumberCategory : public CollectionInterface { - -public: - friend class NumberCategoryModel; - friend class CollectionManagerInterface<ContactMethod>; - - virtual QString name () const override; - virtual QString category () const override; - virtual QVariant icon () const override; - virtual bool isEnabled() const override; - virtual QByteArray id () const override; - virtual int size () const override; - - //Getters - int key ( ) const; - QVariant icon(bool isTracked, bool isPresent = false) const; - - - virtual FlagPack<SupportedFeatures> supportedFeatures() const override; - virtual bool load() override; - - //Setter - void setIcon(const QVariant& pixmap ); - void setName(const QString& name ); - void setKey (const int key ); - -private: - NumberCategory(CollectionMediator<ContactMethod>* mediator, const QString& name); - virtual ~NumberCategory(); - - const QScopedPointer<NumberCategoryPrivate> d_ptr; - Q_DECLARE_PRIVATE(NumberCategory) - -}; diff --git a/src/numbercategorymodel.cpp b/src/numbercategorymodel.cpp deleted file mode 100644 index 46e1ae5f91906d39228bc3efcceb3c899f487701..0000000000000000000000000000000000000000 --- a/src/numbercategorymodel.cpp +++ /dev/null @@ -1,219 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "numbercategorymodel.h" -#include "private/numbercategorymodel_p.h" -#include "contactmethod.h" -#include "numbercategory.h" - -NumberCategoryModel::NumberCategoryModel(QObject* parent) : QAbstractListModel(parent),CollectionManagerInterface(this),d_ptr(new NumberCategoryModelPrivate()) -{ -} - -NumberCategoryModel::~NumberCategoryModel() -{ - delete d_ptr; -} - -NumberCategoryModelPrivate::~NumberCategoryModelPrivate() -{ - for (InternalTypeRepresentation* rep : m_lCategories) - delete rep; -} - -QHash<int,QByteArray> NumberCategoryModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles[Role::KEY] = "key"; - } - return roles; -} - -//Abstract model member -QVariant NumberCategoryModel::data(const QModelIndex& index, int role) const -{ - if (!index.isValid()) return QVariant(); - switch (role) { - case Qt::DisplayRole: { - const QString name = d_ptr->m_lCategories[index.row()]->category->name(); - return name.isEmpty()?tr("Uncategorized"):name; - } - case Qt::DecorationRole: - return d_ptr->m_lCategories[index.row()]->category->icon();//m_pDelegate->icon(m_lCategories[index.row()]->icon); - case Qt::CheckStateRole: - return d_ptr->m_lCategories[index.row()]->enabled?Qt::Checked:Qt::Unchecked; - case Qt::UserRole: - return 'x'+QString::number(d_ptr->m_lCategories[index.row()]->counter); - case Role::KEY: - return d_ptr->m_lCategories[index.row()]->category->key(); - } - return QVariant(); -} - -int NumberCategoryModel::rowCount(const QModelIndex& parent) const -{ - if (parent.isValid()) return 0; - return d_ptr->m_lCategories.size(); -} - -Qt::ItemFlags NumberCategoryModel::flags(const QModelIndex& index) const -{ - return (d_ptr->m_lCategories[index.row()]->category->name().isEmpty() ? Qt::NoItemFlags : Qt::ItemIsEnabled) - | Qt::ItemIsSelectable - | Qt::ItemIsUserCheckable; -} - -bool NumberCategoryModel::setData(const QModelIndex& idx, const QVariant &value, int role) -{ - if (idx.isValid() && role == Qt::CheckStateRole) { - d_ptr->m_lCategories[idx.row()]->enabled = value.toBool(); - emit dataChanged(idx,idx); - return true; - } - return false; -} - -/** - * Manually add a new category - */ -NumberCategory* NumberCategoryModel::addCategory(const QString& name, const QVariant& icon, int key) -{ - NumberCategoryModelPrivate::InternalTypeRepresentation* rep = d_ptr->m_hByName[name]; - if (!name.size()) - return this->other(); - - if (!rep) { - rep = new NumberCategoryModelPrivate::InternalTypeRepresentation(); - rep->counter = 0; - } - - NumberCategory* cat = addCollection<NumberCategory,QString>(name, LoadOptions::NONE); - cat->setKey ( key ); - cat->setIcon( icon ); - - rep->category = cat ; - rep->index = d_ptr->m_lCategories.size(); - rep->enabled = false ; - - this->beginInsertRows(this->nameToIndex(name),d_ptr->m_lCategories.size(), d_ptr->m_lCategories.size()); - d_ptr->m_hToInternal[ cat ] = rep; - d_ptr->m_hByIdx [ key ] = rep; - d_ptr->m_hByName [ name.toLower()] = rep; - d_ptr->m_lCategories << rep; - this->endInsertRows(); - return cat; -} - -NumberCategoryModel& NumberCategoryModel::instance() -{ - static auto instance = new NumberCategoryModel; - return *instance; -} - -/*void NumberCategoryModel::setIcon(int idx, const QVariant& icon) -{ - NumberCategoryModelPrivate::InternalTypeRepresentation* rep = d_ptr->m_hByIdx[idx]; - if (rep) { - rep->category->setIcon(icon); - emit dataChanged(index(d_ptr->m_lCategories.indexOf(rep),0),index(d_ptr->m_lCategories.indexOf(rep),0)); - } -}*/ - -QModelIndex NumberCategoryModel::nameToIndex(const QString& name) const -{ - const QString lower = name.toLower(); - if (!d_ptr->m_hByName[lower]) - return QModelIndex(); - else { - return index(d_ptr->m_hByName[lower]->index,0); - } -} - -///Be sure the category exist, increment the counter -void NumberCategoryModelPrivate::registerNumber(ContactMethod* number) -{ - const QString lower = number->category()->name().toLower(); - NumberCategoryModelPrivate::InternalTypeRepresentation* rep = m_hByName[lower]; - if (!rep) { - NumberCategoryModel::instance().addCategory(number->category()->name(),QVariant()); - rep = m_hByName[lower]; - } - rep->counter++; -} - -void NumberCategoryModelPrivate::unregisterNumber(ContactMethod* number) -{ - const QString lower = number->category()->name().toLower(); - NumberCategoryModelPrivate::InternalTypeRepresentation* rep = m_hByName[lower]; - if (rep) - rep->counter--; -} - -///Get the category (case insensitive) -NumberCategory* NumberCategoryModel::getCategory(const QString& type) -{ - const QString lower = type.toLower(); - if (!lower.size()) - return this->other(); - else { - NumberCategoryModelPrivate::InternalTypeRepresentation* internal = d_ptr->m_hByName[lower]; - if (internal) - return internal->category; - return addCategory(lower,QVariant()); - } -} - - -NumberCategory* NumberCategoryModel::other() -{ - static QString translated = QObject::tr("Other"); - static QString lower = translated.toLower(); - if (instance().d_ptr->m_hByName[lower]) - return instance().d_ptr->m_hByName[lower]->category; - - ///Singleton - static auto other = instance().addCategory(lower, QVariant()); - return other; -} - -int NumberCategoryModelPrivate::getSize(const NumberCategory* cat) const -{ - NumberCategoryModelPrivate::InternalTypeRepresentation* i = m_hToInternal[cat]; - return i ? i->counter : 0; -} - -void NumberCategoryModel::collectionAddedCallback(CollectionInterface* collection) -{ - Q_UNUSED(collection) -} - -bool NumberCategoryModel::addItemCallback(const ContactMethod* item) -{ - Q_UNUSED(item) - return false; -} - -bool NumberCategoryModel::removeItemCallback(const ContactMethod* item) -{ - Q_UNUSED(item) - return false; -} - -#include <numbercategorymodel.moc> diff --git a/src/numbercategorymodel.h b/src/numbercategorymodel.h deleted file mode 100644 index 717d5f5b2753e25a933866b39ce4f579e706583a..0000000000000000000000000000000000000000 --- a/src/numbercategorymodel.h +++ /dev/null @@ -1,76 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" - -#include <QtCore/QAbstractListModel> -#include <QtCore/QVector> -#include "collectionmanagerinterface.h" - -class ContactMethod; -class NumberCategory; -class NumberCategoryModelPrivate; - -/** - * This class manage the ContactMethod categories. Those are usually associated - * with PhoneNumber types used by contacts. - * - * The model is mostly for debugging purpose. The information is also available - * in the CollectionModel. - */ -class LIB_EXPORT NumberCategoryModel : public QAbstractListModel, public CollectionManagerInterface<ContactMethod> { - Q_OBJECT -public: - friend class NumberCategory; - friend class ContactMethod ; - - enum Role { - KEY = 100, - }; - - //Abstract model member - virtual QVariant data (const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount (const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags (const QModelIndex& index ) const override; - virtual bool setData (const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Mutator - NumberCategory* addCategory(const QString& name, const QVariant& icon, int key = -1); - - //Singleton - static NumberCategoryModel& instance(); - - //Getter - QModelIndex nameToIndex(const QString& name ) const; - NumberCategory* getCategory(const QString& type ); - static NumberCategory* other ( ); - -private: - explicit NumberCategoryModel(QObject* parent = nullptr); - ~NumberCategoryModel(); - - NumberCategoryModelPrivate* d_ptr; - - //Re-implementation - virtual void collectionAddedCallback(CollectionInterface* collection) override; - virtual bool addItemCallback (const ContactMethod* item ) override; - virtual bool removeItemCallback (const ContactMethod* item ) override; -}; - diff --git a/src/peerprofilecollection.cpp b/src/peerprofilecollection.cpp deleted file mode 100644 index 834aecc292517df4a23214916e9b0de9b3e27017..0000000000000000000000000000000000000000 --- a/src/peerprofilecollection.cpp +++ /dev/null @@ -1,211 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016-2019 Savoir-faire Linux Inc. * - * Author: Edric Ladent Milaret <edric.ladent-milaret@savoirfairelinux.com>* - * * - * 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 "peerprofilecollection.h" - -//Qt -#include <QtCore/QFile> -#include <QtCore/QDir> -#include <QtCore/QHash> -#include <QtCore/QStandardPaths> -#include <QtCore/QUrl> -#include <QtCore/QVector> -#include <QtCore/QDateTime> - -//Ring -#include "database.h" -#include "private/vcardutils.h" -#include "account.h" -#include "accountmodel.h" -#include "person.h" -#include "contactmethod.h" - -class PeerProfileEditor final : public CollectionEditor<Person> -{ -public: - PeerProfileEditor(CollectionMediator<Person>* m); - virtual bool save (const Person* pers ) override; - virtual bool remove ( const Person* item ) override; - virtual bool edit ( Person* item ) override; - virtual bool addNew (Person* pers ) override; - virtual bool addExisting( const Person* item ) override; - -private: - virtual QVector<Person*> items() const override; - - //Helpers - QString path(const Person* p) const; - - //Attributes - QVector<Person*> m_lItems; -}; - -PeerProfileEditor::PeerProfileEditor(CollectionMediator<Person>* m) : CollectionEditor<Person>(m) -{ - -} - -PeerProfileCollection::PeerProfileCollection(CollectionMediator<Person>* mediator) : -CollectionInterface(new PeerProfileEditor(mediator)) -{ - -} - -PeerProfileCollection::~PeerProfileCollection() -{ - -} - -bool PeerProfileEditor::save(const Person* pers) -{ - const auto& filename = path(pers); - const auto& result = pers->toVCard(); - - QFile file {filename}; - - if (Q_UNLIKELY(!file.open(QIODevice::WriteOnly))) { - qWarning() << "Can't write to" << filename; - return false; - } - - file.write(result); - file.close(); - return true; -} - -bool PeerProfileEditor::remove(const Person* item) -{ - if (QFile::remove(path(item))) { - mediator()->removeItem(item); - return true; - } - - return false; -} - -bool PeerProfileEditor::edit( Person* item) -{ - Q_UNUSED(item) - return false; -} - -bool PeerProfileEditor::addNew( Person* pers) -{ - pers->ensureUid(); - - if (not m_lItems.contains(pers)) { - m_lItems << pers; - mediator()->addItem(pers); - } - save(pers); - return true; -} - -bool PeerProfileEditor::addExisting(const Person* item) -{ - m_lItems << const_cast<Person*>(item); - mediator()->addItem(item); - return true; -} - -QVector<Person*> PeerProfileEditor::items() const -{ - return m_lItems; -} - -QString PeerProfileEditor::path(const Person* p) const -{ - const QDir profilesDir = (lrc::Database::getPath()) + "/peer_profiles/"; - profilesDir.mkpath(profilesDir.path()); - return QString("%1/%2.vcf") - .arg(profilesDir.absolutePath()) - .arg(QString(p->uid())); -} - -QString PeerProfileCollection::name () const -{ - return QObject::tr("Peer profiles"); -} - -QString PeerProfileCollection::category () const -{ - return QObject::tr("Peers Profiles Collection"); -} - -QVariant PeerProfileCollection::icon() const -{ - return QVariant(); -} - -bool PeerProfileCollection::isEnabled() const -{ - return true; -} - -bool PeerProfileCollection::load() -{ - const QDir profilesDir = (lrc::Database::getPath()) + "/peer_profiles/"; - - const QStringList entries = profilesDir.entryList({QStringLiteral("*.vcf")}, QDir::Files); - - foreach (const QString& item , entries) { - auto filePath = profilesDir.path() + '/' + item; - - // create Person - auto personProfile = new Person(this); - QList<Account*> accs; - VCardUtils::mapToPerson(personProfile, QUrl(filePath), &accs); - editor<Person>()->addExisting(personProfile); - - // set last used time based on last modified of vCard file; this is in case there has been - // no other interactions with these CMs - auto lastUsed = QFileInfo(filePath).lastModified(); - for (auto cm : personProfile->phoneNumbers()) { - cm->setLastUsed(lastUsed.toTime_t()); - } - } - - return true; -} - -bool PeerProfileCollection::reload() -{ - return true; -} - -FlagPack<CollectionInterface::SupportedFeatures> PeerProfileCollection::supportedFeatures() const -{ - return - CollectionInterface::SupportedFeatures::NONE | - CollectionInterface::SupportedFeatures::LOAD | - CollectionInterface::SupportedFeatures::CLEAR | - CollectionInterface::SupportedFeatures::REMOVE | - CollectionInterface::SupportedFeatures::MANAGEABLE | - CollectionInterface::SupportedFeatures::ADD ; -} - -bool PeerProfileCollection::clear() -{ - QFile::remove((lrc::Database::getPath()) + "/peer_profiles/"); - return true; -} - -QByteArray PeerProfileCollection::id() const -{ - return "ppc"; -} diff --git a/src/person.cpp b/src/person.cpp deleted file mode 100644 index c1bc43baf84addf28e21c45c92323bd0501ba9e5..0000000000000000000000000000000000000000 --- a/src/person.cpp +++ /dev/null @@ -1,753 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -//Parent -#include "person.h" - -//Qt -#include <QtCore/QDateTime> - -//Ring library -#include "contactmethod.h" -#include "accountmodel.h" -#include "certificatemodel.h" -#include "collectioninterface.h" -#include "account.h" -#include "private/vcardutils.h" -#include "personmodel.h" -#include "numbercategorymodel.h" -#include "numbercategory.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "private/person_p.h" -#include "mime.h" - -// Std -#include <random> - -class AddressPrivate final -{ -public: - ~AddressPrivate() {} - - QString addressLine; - QString city; - QString zipCode; - QString state; - QString country; - QString type; -}; - -Person::Address::Address() : d_ptr(new AddressPrivate()) -{ - -} - -Person::Address::~Address() -{ - //delete d_ptr; //FIXME ASAN doesn't like for some reasons, but also report a leak -} - -QString Person::Address::addressLine() const -{ - return d_ptr->addressLine; -} - -QString Person::Address::city() const -{ - return d_ptr->city; -} - -QString Person::Address::zipCode() const -{ - return d_ptr->zipCode; -} - -QString Person::Address::state() const -{ - return d_ptr->state; -} - -QString Person::Address::country() const -{ - return d_ptr->country; -} - -QString Person::Address::type() const -{ - return d_ptr->type; -} - -void Person::Address::setAddressLine(const QString& value) -{ - d_ptr->addressLine = value; -} - -void Person::Address::setCity(const QString& value) -{ - d_ptr->city = value; -} - -void Person::Address::setZipCode(const QString& value) -{ - d_ptr->zipCode = value; -} - -void Person::Address::setState(const QString& value) -{ - d_ptr->state = value; -} - -void Person::Address::setCountry(const QString& value) -{ - d_ptr->country = value; -} - -void Person::Address::setType(const QString& value) -{ - d_ptr->type = value; -} - -QString PersonPrivate::filterString() -{ - if (m_CachedFilterString.size()) - return m_CachedFilterString; - - //Also filter by phone numbers, accents are negligible - foreach(const ContactMethod* n , m_Numbers) { - m_CachedFilterString += n->uri(); - } - - //Strip non essential characters like accents from the filter string - foreach(const QChar& char2,(m_FormattedName+'\n'+m_Organization+'\n'+m_Group+'\n'+ - m_Department+'\n'+m_PreferredEmail).toLower().normalized(QString::NormalizationForm_KD) ) { - if (!char2.combiningClass()) - m_CachedFilterString += char2; - } - - return m_CachedFilterString; -} - -void PersonPrivate::changed() -{ - m_CachedFilterString.clear(); - foreach (Person* c,m_lParents) { - emit c->changed(); - } -} - -void PersonPrivate::presenceChanged( ContactMethod* n ) -{ - foreach (Person* c,m_lParents) { - emit c->presenceChanged(n); - } -} - -void PersonPrivate::statusChanged ( bool s ) -{ - foreach (Person* c,m_lParents) { - emit c->statusChanged(s); - } -} - -void PersonPrivate::phoneNumbersChanged() -{ - foreach (Person* c,m_lParents) { - emit c->phoneNumbersChanged(); - } -} - -void PersonPrivate::phoneNumbersAboutToChange() -{ - foreach (Person* c,m_lParents) { - emit c->phoneNumbersAboutToChange(); - } -} - -void PersonPrivate::registerContactMethod(ContactMethod* m) -{ - m_HiddenContactMethods << m; - connect(m, &ContactMethod::lastUsedChanged, this, &PersonPrivate::slotLastUsedTimeChanged); - - if (m->lastUsed() > m_LastUsed) - slotLastUsedTimeChanged(m->lastUsed()); -} - -PersonPrivate::PersonPrivate(Person* contact) : QObject(nullptr), - m_Numbers(),m_DisplayPhoto(false),m_Active(true),m_isPlaceHolder(false), - m_LastUsed(0),m_LastUsedInit(false), q_ptr(contact) -{ - moveToThread(QCoreApplication::instance()->thread()); - setParent(contact); -} - -PersonPrivate::~PersonPrivate() -{ -} - -///Constructor -Person::Person(CollectionInterface* parent): ItemBase(nullptr), - d_ptr(new PersonPrivate(this)) -{ - if(!parent) return; - setCollection(parent); - - d_ptr->m_isPlaceHolder = false; - d_ptr->m_lParents << this; -} - -Person::Person(const QByteArray& content, Person::Encoding encoding, CollectionInterface* parent) - : ItemBase(nullptr), d_ptr(new PersonPrivate(this)) -{ - if(!parent) return; - setCollection(parent); - d_ptr->m_isPlaceHolder = false; - d_ptr->m_lParents << this; - switch (encoding) { - case Person::Encoding::UID: - setUid(content); - break; - case Person::Encoding::vCard: - if (!VCardUtils::mapToPerson(this, content)) { - qDebug() << "Loading person failed"; - } - break; - }; -} - -/** - * Copy constructor, useful when transferring a contact between collections - * - * For example, converting a trust request to GMail contact without forcing - * a slow vCard conversion. - * - * This create a COPY of the person details, using shared attributes between - * multiple person with multiple collection is currently not supported (but - * would be easy to enable if the need arise). - */ -Person::Person(const Person& other) noexcept : ItemBase(nullptr), -d_ptr(new PersonPrivate(this)) -{ - d_ptr->m_FirstName = other.d_ptr->m_FirstName ; - d_ptr->m_SecondName = other.d_ptr->m_SecondName ; - d_ptr->m_NickName = other.d_ptr->m_NickName ; - d_ptr->m_vPhoto = other.d_ptr->m_vPhoto ; - d_ptr->m_FormattedName = other.d_ptr->m_FormattedName ; - d_ptr->m_PreferredEmail = other.d_ptr->m_PreferredEmail ; - d_ptr->m_Organization = other.d_ptr->m_Organization ; - d_ptr->m_Uid = other.d_ptr->m_Uid ; - d_ptr->m_Group = other.d_ptr->m_Group ; - d_ptr->m_Department = other.d_ptr->m_Department ; - d_ptr->m_DisplayPhoto = other.d_ptr->m_DisplayPhoto ; - d_ptr->m_Numbers = other.d_ptr->m_Numbers ; - d_ptr->m_Active = other.d_ptr->m_Active ; - d_ptr->m_isPlaceHolder = other.d_ptr->m_isPlaceHolder ; - d_ptr->m_lAddresses = other.d_ptr->m_lAddresses ; - d_ptr->m_lCustomAttributes = other.d_ptr->m_lCustomAttributes ; - d_ptr->m_LastUsed = other.d_ptr->m_LastUsed ; - d_ptr->m_LastUsedInit = other.d_ptr->m_LastUsedInit ; - d_ptr->m_HiddenContactMethods = other.d_ptr->m_HiddenContactMethods; -} - -///Updates an existing contact from vCard info -void Person::updateFromVCard(const QByteArray& content) -{ - // empty existing contact methods first - setContactMethods(ContactMethods()); - if (!VCardUtils::mapToPerson(this, content)) { - qWarning() << "Updating person failed"; - } -} - -///Destructor -Person::~Person() -{ - //Unregister itself from the D-Pointer list - d_ptr->m_lParents.removeAll(this); - - if (!d_ptr->m_lParents.size()) { - delete d_ptr; - } -} - -///Get the phone number list -const Person::ContactMethods& Person::phoneNumbers() const -{ - return d_ptr->m_Numbers; -} - -///Get the nickname -const QString& Person::nickName() const -{ - return d_ptr->m_NickName; -} - -///Get the firstname -const QString& Person::firstName() const -{ - return d_ptr->m_FirstName; -} - -///Get the second/family name -const QString& Person::secondName() const -{ - return d_ptr->m_SecondName; -} - -///Get the photo -const QVariant Person::photo() const -{ - return d_ptr->m_vPhoto; -} - -///Get the formatted name -const QString& Person::formattedName() const -{ - return d_ptr->m_FormattedName; -} - -///Get the organisation -const QString& Person::organization() const -{ - return d_ptr->m_Organization; -} - -///Get the preferred email -const QString& Person::preferredEmail() const -{ - return d_ptr->m_PreferredEmail; -} - -///Get the unique identifier (used for drag and drop) -const QByteArray& Person::uid() const -{ - return d_ptr->m_Uid; -} - -///Get the group -const QString& Person::group() const -{ - return d_ptr->m_Group; -} - -const QString& Person::department() const -{ - return d_ptr->m_Department; -} - -/// Get the last ContactMethod used with that person. -ContactMethod* Person::lastUsedContactMethod() const -{ - auto lastUsed = std::max_element(phoneNumbers().begin(), phoneNumbers().end(), - [] (ContactMethod* a, ContactMethod* b) { return (a->lastUsed() < b->lastUsed()); } - ); - return *lastUsed; -} - -///Set the phone number (type and number) -void Person::setContactMethods(ContactMethods numbers) -{ - d_ptr->phoneNumbersAboutToChange(); - for (ContactMethod* n : d_ptr->m_Numbers) { - disconnect(n,SIGNAL(presentChanged(bool)),this,SLOT(slotPresenceChanged())); - disconnect(n, &ContactMethod::lastUsedChanged, d_ptr, &PersonPrivate::slotLastUsedTimeChanged); - disconnect(n, &ContactMethod::unreadTextMessageCountChanged, d_ptr, &PersonPrivate::changed); - disconnect(n, &ContactMethod::callAdded, d_ptr, &PersonPrivate::slotCallAdded); - } - d_ptr->m_Numbers = numbers; - - for (ContactMethod* n : d_ptr->m_Numbers) { - connect(n,SIGNAL(presentChanged(bool)),this,SLOT(slotPresenceChanged())); - connect(n, &ContactMethod::lastUsedChanged, d_ptr, &PersonPrivate::slotLastUsedTimeChanged); - connect(n, &ContactMethod::unreadTextMessageCountChanged, d_ptr, &PersonPrivate::changed); - } - - d_ptr->phoneNumbersChanged(); - d_ptr->changed(); - - //Allow incoming calls from those numbers - const QList<Account*> ringAccounts = AccountModel::instance().getAccountsByProtocol(Account::Protocol::RING); - QStringList certIds; - for (ContactMethod* n : d_ptr->m_Numbers) { - if (n->uri().protocolHint() == URI::ProtocolHint::RING) - certIds << n->uri().userinfo(); // certid must only contain the hash, no scheme - } - - foreach(const QString& hash , certIds) { - Certificate* cert = CertificateModel::instance().getCertificateFromId(hash); - if (cert) { - for (Account* a : ringAccounts) { - if (a->allowIncomingFromContact()) - a->allowCertificate(cert); - } - } - } -} - -///Set the nickname -void Person::setNickName(const QString& name) -{ - d_ptr->m_NickName = name; - d_ptr->changed(); -} - -///Set the first name -void Person::setFirstName(const QString& name) -{ - d_ptr->m_FirstName = name; - setObjectName(formattedName()); - d_ptr->changed(); -} - -///Set the family name -void Person::setFamilyName(const QString& name) -{ - d_ptr->m_SecondName = name; - setObjectName(formattedName()); - d_ptr->changed(); -} - -///Set the Photo/Avatar -void Person::setPhoto(const QVariant& photo) -{ - d_ptr->m_vPhoto = photo; - d_ptr->changed(); -} - -///Set the formatted name (display name) -void Person::setFormattedName(const QString& name) -{ - d_ptr->m_FormattedName = name; - d_ptr->changed(); -} - -///Set the organisation / business -void Person::setOrganization(const QString& name) -{ - d_ptr->m_Organization = name; - d_ptr->changed(); -} - -///Set the default email -void Person::setPreferredEmail(const QString& name) -{ - d_ptr->m_PreferredEmail = name; - d_ptr->changed(); -} - -///Set UID -void Person::setUid(const QByteArray& id) -{ - d_ptr->m_Uid = id; - d_ptr->changed(); -} - -///Set Group -void Person::setGroup(const QString& name) -{ - d_ptr->m_Group = name; - d_ptr->changed(); -} - -///Set department -void Person::setDepartment(const QString& name) -{ - d_ptr->m_Department = name; - d_ptr->changed(); -} - -///Return if one of the ContactMethod is present -bool Person::isPresent() const -{ - foreach(const ContactMethod* n,d_ptr->m_Numbers) { - if (n->isPresent()) - return true; - } - return false; -} - -///Return if one of the ContactMethod is tracked -bool Person::isTracked() const -{ - foreach(const ContactMethod* n,d_ptr->m_Numbers) { - if (n->isTracked()) - return true; - } - return false; -} - -bool Person::isPlaceHolder() const -{ - return d_ptr->m_isPlaceHolder; -} - -/** Get the last time this person was contacted - * @warning This method complexity is O(N) - * @todo Implement some caching - */ -time_t Person::lastUsedTime() const -{ - if (!d_ptr->m_LastUsedInit) { - for (int i=0;i<phoneNumbers().size();i++) { - if (phoneNumbers().at(i)->lastUsed() > d_ptr->m_LastUsed) - d_ptr->m_LastUsed = phoneNumbers().at(i)->lastUsed(); - } - d_ptr->m_LastUsedInit = true; - if (d_ptr->m_LastUsed) - emit lastUsedTimeChanged(d_ptr->m_LastUsed); - } - return d_ptr->m_LastUsed; -} - -///Return if one of the ContactMethod support presence -bool Person::supportPresence() const -{ - foreach(const ContactMethod* n,d_ptr->m_Numbers) { - if (n->supportPresence()) - return true; - } - return false; -} - -///Return true if there is a change one if the account can be used to reach that person -bool Person::isReachable() const -{ - if (!d_ptr->m_Numbers.size()) - return false; - - foreach (const ContactMethod* n, d_ptr->m_Numbers) { - if (n->isReachable()) - return true; - } - return false; -} - -bool Person::hasBeenCalled() const -{ - foreach( ContactMethod* cm, phoneNumbers()) { - if (cm->callCount()) - return true; - } - - return false; -} - -/** - * Return if one of the contact method has a recording - * - * @todo Implement AUDIO, VIDEO and FILE, The information can be obtained by \ - * foreach looping the contact methods calls, but this is overly expensive. \ - * some ContactMethod level caching need to be implemented and connected to new\ - * recording signals. - */ -bool Person::hasRecording(media::Media::Type type, media::Media::Direction direction) const -{ - Q_UNUSED(direction) //TODO implement - - switch (type) { - case media::Media::Type::AUDIO: - case media::Media::Type::VIDEO: - return false; //TODO implement -case media::Media::Type::TEXT: - return false; - case media::Media::Type::FILE: - case media::Media::Type::COUNT__: - break; - } - - return false; -} - -///Recomputing the filter string is heavy, cache it -QString Person::filterString() const -{ - return d_ptr->filterString(); -} - -///Get the role value -QVariant Person::roleData(int role) const -{ - switch (role) { - case Qt::DisplayRole: - case Qt::EditRole: - case static_cast<int>(Ring::Role::Name): - return QVariant(formattedName()); - case static_cast<int>(Ring::Role::Number): - { - auto cm = lastUsedContactMethod(); - return cm ? cm->bestId() : QString(); - } - case Qt::DecorationRole: - return GlobalInstances::pixmapManipulator().decorationRole(this); - case static_cast<int>(Person::Role::Organization): - return QVariant(organization()); - case static_cast<int>(Person::Role::Group): - return QVariant(group()); - case static_cast<int>(Person::Role::Department): - return QVariant(department()); - case static_cast<int>(Person::Role::PreferredEmail): - return QVariant(preferredEmail()); - case static_cast<int>(Ring::Role::FormattedLastUsed): - case static_cast<int>(Person::Role::FormattedLastUsed): - return QVariant(); - case static_cast<int>(Ring::Role::IndexedLastUsed): - case static_cast<int>(Person::Role::IndexedLastUsed): - return QVariant(); - case static_cast<int>(Ring::Role::Object): - case static_cast<int>(Person::Role::Object): - return QVariant::fromValue(const_cast<Person*>(this)); - case static_cast<int>(Ring::Role::ObjectType): - return QVariant::fromValue(Ring::ObjectType::Person); - case static_cast<int>(Ring::Role::LastUsed): - case static_cast<int>(Person::Role::DatedLastUsed): - return QVariant(QDateTime::fromTime_t( lastUsedTime())); - case static_cast<int>(Person::Role::Filter): - return filterString(); - case static_cast<int>(Ring::Role::IsPresent): - return isPresent(); - case static_cast<int>(Person::Role::IdOfLastCMUsed): - { - auto cm = lastUsedContactMethod(); - return cm ? cm->bestId() : QString(); - } - case static_cast<int>(Ring::Role::UnreadTextMessageCount): - { - int unread = 0; - return unread; - } - break; - default: - break; - } - - return QVariant(); -} - -QMimeData* Person::mimePayload() const -{ - return RingMimes::payload(nullptr, nullptr, this); -} - -///Callback when one of the phone number presence change -void Person::slotPresenceChanged() -{ - d_ptr->changed(); -} - -///Create a placeholder contact, it will eventually be replaced when the real one is loaded -PersonPlaceHolder::PersonPlaceHolder(const QByteArray& uid):d_ptr(nullptr) -{ - setUid(uid); - Person::d_ptr->m_isPlaceHolder = true; -} - -/** - * Sometime, items will use contacts before they are loaded. - * - * Once loaded, those pointers need to be upgraded to the real contact. - */ -bool PersonPlaceHolder::merge(Person* contact) -{ - if ((!contact) || ((*contact) == this)) - return false; - - PersonPrivate* currentD = Person::d_ptr; - replaceDPointer(contact); - currentD->m_lParents.removeAll(this); - - if (!currentD->m_lParents.size()) - delete currentD; - return true; -} - -void Person::replaceDPointer(Person* c) -{ - - if (d_ptr->m_LastUsed > c->lastUsedTime()) { - c->d_ptr->m_LastUsed = d_ptr->m_LastUsed; - emit c->lastUsedTimeChanged(d_ptr->m_LastUsed); - } - - this->d_ptr = c->d_ptr; - d_ptr->m_lParents << this; - emit changed(); - emit rebased(c); -} - -bool Person::operator==(const Person* other) const -{ - return other && this->d_ptr == other->d_ptr; -} - -bool Person::operator==(const Person& other) const -{ - return this->d_ptr == other.d_ptr; -} - -///Add a new address to this contact -void Person::addAddress(const Person::Address& addr) -{ - d_ptr->m_lAddresses << addr; -} - -///Add custom fields for contact profiles -void Person::addCustomField(const QString& key, const QString& value) -{ - d_ptr->m_lCustomAttributes.insert(key, value); -} - -const QByteArray Person::toVCard(QList<Account*> accounts, const std::string& avatar, const std::string& newName) const -{ - qDebug("warning: use of deprecated Person::toVCard (this is NOP, use NewAccountModel::accountVCard instead)"); - return {}; -} - -void PersonPrivate::slotLastUsedTimeChanged(::time_t t) -{ - m_LastUsed = t; - - foreach (Person* c,m_lParents) { - emit c->lastUsedTimeChanged(t); - } -} - -void PersonPrivate::slotCallAdded(Call *call) -{ - foreach (Person* c,m_lParents) { - emit c->callAdded(call); - } -} - -/** - * ensureUid ensures an unique Id. - */ -void -Person::ensureUid() -{ - static std::random_device rdev; - static std::seed_seq seq {rdev(), rdev()}; - static std::mt19937_64 rand {seq}; - static std::uniform_int_distribution<uint64_t> id_generator; - - while (d_ptr->m_Uid.isEmpty() - or (PersonModel::instance().getPersonByUid(d_ptr->m_Uid) - && PersonModel::instance().getPersonByUid(d_ptr->m_Uid) != this)) { - d_ptr->m_Uid = std::to_string(id_generator(rand)).c_str(); - } -} diff --git a/src/person.h b/src/person.h deleted file mode 100644 index 7483920722f91f2e31797add21fbe69689e1b5e8..0000000000000000000000000000000000000000 --- a/src/person.h +++ /dev/null @@ -1,220 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> -#include <QtCore/QVariant> -#include <time.h> -#include <itembase.h> -#include <media/media.h> - -//Ring -#include "itemdataroles.h" -class ContactMethod; -class PersonPrivate; -class AddressPrivate; -class Account; -class CollectionInterface; -class PersonPlaceHolderPrivate; - -#include "typedefs.h" - -///Person: Abstract version of a contact -class LIB_EXPORT Person : public ItemBase -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - - friend class ContactMethod; - -public: - - enum class Role { - Organization = static_cast<int>(Ring::Role::UserRole) + 100, - Group , - Department , - PreferredEmail , - FormattedLastUsed , - IndexedLastUsed , - DatedLastUsed , - IdOfLastCMUsed , - Object , - Filter , //All roles, all at once - DropState = static_cast<int>(Ring::Role::DropState), //State for drag and drop - }; - - ///@enum Encoding How to decode the person content payload - enum class Encoding { - UID , /*!< The bytearray only has an unique identifier */ - vCard, /*!< The bytearray contain a RFC 6868 compliant vCard */ - }; - - ///Represent the physical address of a contact - class Address { - public: - explicit Address(); - virtual ~Address(); - - //Getters - QString addressLine() const; - QString city () const; - QString zipCode () const; - QString state () const; - QString country () const; - QString type () const; - - //Setters - void setAddressLine(const QString& value); - void setCity (const QString& value); - void setZipCode (const QString& value); - void setState (const QString& value); - void setCountry (const QString& value); - void setType (const QString& value); - - private: - AddressPrivate* d_ptr; - }; - - typedef QVector<ContactMethod*> ContactMethods; - - //Properties - Q_PROPERTY( ContactMethods phoneNumbers READ phoneNumbers WRITE setContactMethods ) - Q_PROPERTY( QString nickName READ nickName WRITE setNickName ) - Q_PROPERTY( QString firstName READ firstName WRITE setFirstName ) - Q_PROPERTY( QString secondName READ secondName WRITE setFamilyName ) - Q_PROPERTY( QString formattedName READ formattedName WRITE setFormattedName ) - Q_PROPERTY( QString organization READ organization WRITE setOrganization ) - Q_PROPERTY( QByteArray uid READ uid WRITE setUid ) - Q_PROPERTY( QString preferredEmail READ preferredEmail WRITE setPreferredEmail ) - Q_PROPERTY( QVariant photo READ photo WRITE setPhoto ) - Q_PROPERTY( QString group READ group WRITE setGroup ) - Q_PROPERTY( QString department READ department WRITE setDepartment ) - Q_PROPERTY( time_t lastUsedTime READ lastUsedTime ) - Q_PROPERTY( bool hasBeenCalled READ hasBeenCalled ) - - //Mutator - Q_INVOKABLE void addAddress(const Address& addr); - Q_INVOKABLE void addCustomField(const QString& key, const QString& value); - Q_INVOKABLE const QByteArray toVCard(QList<Account*> accounts = {}, const std::string& avatar = "", const std::string& newName = "") const; - -protected: - //The D-Pointer can be shared if a PlaceHolderPerson is merged with a real one - PersonPrivate* d_ptr; - Q_DECLARE_PRIVATE(Person) - - void replaceDPointer(Person* other); - -public: - //Constructors & Destructors - explicit Person(CollectionInterface* parent = nullptr); - Person(const QByteArray& content, Person::Encoding encoding = Encoding::UID, CollectionInterface* parent = nullptr); - Person(const Person& other) noexcept; - virtual ~Person(); - - //Getters - const ContactMethods& phoneNumbers() const; - const QString& nickName () const; - const QString& firstName () const; - const QString& secondName () const; - const QString& formattedName () const; - const QString& organization () const; - const QByteArray& uid () const; - const QString& preferredEmail () const; - const QVariant photo () const; - const QString& group () const; - const QString& department () const; - time_t lastUsedTime () const; - ContactMethod* lastUsedContactMethod() const; - - Q_INVOKABLE QVariant roleData (int role) const; - Q_INVOKABLE QMimeData* mimePayload( ) const; - - //Cache - QString filterString () const; - - //Number related getters (proxies) - bool isPresent () const; - bool isTracked () const; - bool supportPresence () const; - bool isReachable () const; - bool isPlaceHolder () const; - bool hasBeenCalled () const; - - bool hasRecording(media::Media::Type type, media::Media::Direction direction) const; - - //Setters - void setContactMethods ( ContactMethods ); - void setFormattedName ( const QString& name ); - void setNickName ( const QString& name ); - void setFirstName ( const QString& name ); - void setFamilyName ( const QString& name ); - void setOrganization ( const QString& name ); - void setPreferredEmail ( const QString& name ); - void setGroup ( const QString& name ); - void setDepartment ( const QString& name ); - void setUid ( const QByteArray& id ); - void setPhoto ( const QVariant& photo ); - void ensureUid ( ); - - //Updates an existing contact from vCard info - void updateFromVCard(const QByteArray& content); - - //Operator - bool operator==(const Person* other) const; - bool operator==(const Person& other) const; - -private Q_SLOTS: - void slotPresenceChanged(); //TODO remove - -Q_SIGNALS: - ///The presence status of a contact method changed - void presenceChanged ( ContactMethod* ); - ///The person presence status changed - void statusChanged ( bool ); - ///The person properties changed - void changed ( ); - ///The number of and/or the contact methods themselves have changed - void phoneNumbersChanged ( ); - ///The number of and/or the contact methods themselvesd are about to change - void phoneNumbersAboutToChange ( ); - ///The person data were merged from another source - void rebased ( Person* ); - ///The last time there was an interaction with this person changed - void lastUsedTimeChanged ( long long ) const; - ///A new call used a ContactMethod associated with this Person - void callAdded ( Call* ); - -protected: - //Presence secret methods - void updatePresenceInformations(const QString& uri, bool status, const QString& message); -}; - -class LIB_EXPORT PersonPlaceHolder : public Person { - Q_OBJECT -public: - explicit PersonPlaceHolder(const QByteArray& uid); - bool merge(Person* contact); -private: - PersonPlaceHolderPrivate* d_ptr; - Q_DECLARE_PRIVATE(PersonPlaceHolder) -}; - -Q_DECLARE_METATYPE(Person*) diff --git a/src/personmodel.cpp b/src/personmodel.cpp deleted file mode 100644 index 0824dc57428d97c8bff46750d5f2cf8f8f9e1710..0000000000000000000000000000000000000000 --- a/src/personmodel.cpp +++ /dev/null @@ -1,385 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -//Parent -#include "personmodel.h" - -//Std -#include <memory> -#include <vector> - -//Ring library -#include "person.h" -#include "call.h" -#include "uri.h" -#include "contactmethod.h" -#include "collectioninterface.h" -#include "collectionmodel.h" -#include "collectioneditor.h" - -//Qt -#include <QtCore/QHash> -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> - -class PersonItemNode -{ -public: - - enum class NodeType { - PERSON, - NUMBER, - }; - - PersonItemNode(Person* p, const NodeType type); - PersonItemNode(ContactMethod* cm, const NodeType type); - std::unique_ptr<Person> m_pPerson; - ContactMethod* m_pContactMethod {nullptr}; - int m_Index; - std::vector<std::unique_ptr<PersonItemNode>> m_lChildren; - PersonItemNode* m_pParent {nullptr}; - NodeType m_Type; - -}; - -class PersonModelPrivate final : public QObject -{ - Q_OBJECT -public: - PersonModelPrivate(PersonModel* parent); - - //Attributes -// QVector<CollectionInterface*> m_lBackends; - QHash<QByteArray,PersonPlaceHolder*> m_hPlaceholders; - - //Indexes - QHash<QByteArray,Person*> m_hPersonsByUid; - std::vector<std::unique_ptr<PersonItemNode>> m_lPersons; - -private: - PersonModel* q_ptr; -// void slotPersonAdded(Person* c); - -public Q_SLOTS: - void slotLastUsedTimeChanged(time_t t) const; -}; - -PersonItemNode::PersonItemNode(Person* p, const NodeType type) : -m_Type(type),m_pPerson(p) -{ - -} - -PersonItemNode::PersonItemNode(ContactMethod* cm, const NodeType type) : -m_Type(type),m_pContactMethod(cm) -{ - -} - -PersonModelPrivate::PersonModelPrivate(PersonModel* parent) : QObject(parent), q_ptr(parent) -{ - -} - -///Constructor -PersonModel::PersonModel(QObject* par) : QAbstractItemModel(par?par:QCoreApplication::instance()), CollectionManagerInterface<Person>(this), -d_ptr(new PersonModelPrivate(this)) -{ - setObjectName("PersonModel"); -} - -///Destructor -PersonModel::~PersonModel() -{ - d_ptr->m_hPersonsByUid.clear(); -} - -PersonModel& PersonModel::instance() -{ - static auto instance = new PersonModel(QCoreApplication::instance()); - return *instance; -} - -/***************************************************************************** - * * - * Model * - * * - ****************************************************************************/ - -QHash<int,QByteArray> PersonModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles[ (int)Person::Role::Organization ] = "organization"; - roles[ (int)Person::Role::Group ] = "group"; - roles[ (int)Person::Role::Department ] = "department"; - roles[ (int)Person::Role::PreferredEmail ] = "preferredEmail"; - roles[ (int)Person::Role::FormattedLastUsed ] = "formattedLastUsed"; - roles[ (int)Person::Role::IndexedLastUsed ] = "indexedLastUsed"; - roles[ (int)Person::Role::DatedLastUsed ] = "datedLastUsed"; - roles[ (int)Person::Role::Filter ] = "filter"; //All roles, all at once - roles[ (int)Person::Role::DropState ] = "dropState"; //State for drag and drop - } - return roles; -} - -bool PersonModel::setData( const QModelIndex& idx, const QVariant &value, int role) -{ - Q_UNUSED(idx) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -QVariant PersonModel::data( const QModelIndex& idx, int role) const -{ - if (!idx.isValid()) - return QVariant(); - const PersonItemNode* c = static_cast<PersonItemNode*>(idx.internalPointer()); - - switch(c->m_Type) { - case PersonItemNode::NodeType::PERSON: - return c->m_pPerson->roleData(role); - case PersonItemNode::NodeType::NUMBER: - return c->m_pContactMethod->roleData(role); - } - return QVariant(); -} - -QVariant PersonModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - Q_UNUSED(section) - if (orientation == Qt::Horizontal && role == Qt::DisplayRole) - return QVariant(tr("Persons")); - return QVariant(); -} - -int PersonModel::rowCount( const QModelIndex& par ) const -{ - if (!par.isValid()) { - return d_ptr->m_lPersons.size(); - } - else if (!par.parent().isValid() && static_cast<unsigned>(par.row()) < d_ptr->m_lPersons.size()) { - return d_ptr->m_lPersons[par.row()]->m_lChildren.size(); - } - return 0; -} - -Qt::ItemFlags PersonModel::flags( const QModelIndex& idx ) const -{ - if (!idx.isValid()) - return Qt::NoItemFlags; - return Qt::ItemIsEnabled | ((idx.parent().isValid())?Qt::ItemIsSelectable:Qt::ItemIsEnabled); -} - -int PersonModel::columnCount ( const QModelIndex& par) const -{ - Q_UNUSED(par) - return 1; -} - -QModelIndex PersonModel::parent( const QModelIndex& idx) const -{ - if (!idx.isValid()) - return QModelIndex(); - PersonItemNode* modelItem = (PersonItemNode*)idx.internalPointer(); - if (modelItem && modelItem->m_pParent) { - return createIndex(modelItem->m_pParent->m_Index,0,modelItem->m_pParent); - } - return QModelIndex(); -} - -QModelIndex PersonModel::index( int row, int column, const QModelIndex& par) const -{ - if (row >= 0 && column >= 0) { - if (!par.isValid() && d_ptr->m_lPersons.size() > static_cast<unsigned>(row)) { - return createIndex(row,column,d_ptr->m_lPersons[row].get()); - } else if (par.isValid() && d_ptr->m_lPersons[par.row()]->m_lChildren.size() > static_cast<unsigned>(row)) { - PersonItemNode* modelItem = (PersonItemNode*)par.internalPointer(); - if (modelItem && static_cast<unsigned>(row) < modelItem->m_lChildren.size()) - return createIndex(row,column,modelItem->m_lChildren[row].get()); - } - } - return QModelIndex(); -} - -/***************************************************************************** - * * - * Mutator * - * * - ****************************************************************************/ - - -///Find contact by UID -Person* PersonModel::getPersonByUid(const QByteArray& uid) -{ - return d_ptr->m_hPersonsByUid[uid]; -} - -/** - * Create a temporary contact or return the existing one for an UID - * This temporary contact should eventually be merged into the real one - */ -Person* PersonModel::getPlaceHolder(const QByteArray& uid ) -{ - Person* ct = d_ptr->m_hPersonsByUid[uid]; - - //Do not create a placeholder if the real deal exist - if (ct) { - return ct; - } - - //Do not re-create if it already exist - ct = d_ptr->m_hPlaceholders[uid]; - if (ct) - return ct; - - PersonPlaceHolder* ct2 = new PersonPlaceHolder(uid); - - d_ptr->m_hPlaceholders[ct2->uid()] = ct2; - return ct2; -} - -void PersonModel::collectionAddedCallback(CollectionInterface* backend) -{ - Q_UNUSED(backend) -} - -bool PersonModel::addItemCallback(const Person* c) -{ - //Add to the model - beginInsertRows(QModelIndex(),d_ptr->m_lPersons.size(),d_ptr->m_lPersons.size()); - d_ptr->m_lPersons.emplace_back(new PersonItemNode {const_cast<Person*>(c), PersonItemNode::NodeType::PERSON}); - auto& inode = *d_ptr->m_lPersons.back(); - inode.m_Index = d_ptr->m_lPersons.size() - 1; - d_ptr->m_hPersonsByUid[c->uid()] = const_cast<Person*>(c); - endInsertRows(); - emit newPersonAdded(c); - - //Add the contact method nodes - const QModelIndex& idx = index(inode.m_Index,0); - beginInsertRows(idx,0,c->phoneNumbers().size()); - inode.m_lChildren.reserve(c->phoneNumbers().size()); - for (auto& m : c->phoneNumbers()) { - inode.m_lChildren.emplace_back(new PersonItemNode {m, PersonItemNode::NodeType::NUMBER}); - auto& child = *inode.m_lChildren.back().get(); - child.m_Index = inode.m_lChildren.size() - 1; - child.m_pParent = &inode; //TODO support adding new contact methods on the fly - } - endInsertRows(); - - //Deprecate the placeholder - if (d_ptr->m_hPlaceholders.contains(c->uid())) { - PersonPlaceHolder* c2 = d_ptr->m_hPlaceholders[c->uid()]; - if (c2) { - c2->merge(const_cast<Person*>(c)); - d_ptr->m_hPlaceholders[c->uid()] = nullptr; - } - } - - connect(c, &Person::lastUsedTimeChanged, d_ptr.data(), &PersonModelPrivate::slotLastUsedTimeChanged); - - if (c->lastUsedTime()) - emit lastUsedTimeChanged(const_cast<Person*>(c), c->lastUsedTime()); - - return true; -} - -bool PersonModel::removeItemCallback(const Person* item) -{ - for (unsigned int nodeIdx = 0; nodeIdx < d_ptr->m_lPersons.size(); ++nodeIdx) { - auto person = d_ptr->m_lPersons[nodeIdx]->m_pPerson.get(); - if (person == item) { - - for ( const auto cm : person->phoneNumbers() ) - // cm is not linked to any person anymore - cm->setPerson(nullptr); - - // Remove contact - beginRemoveRows(QModelIndex(), nodeIdx, nodeIdx); - d_ptr->m_lPersons[nodeIdx].release(); - d_ptr->m_lPersons.erase(d_ptr->m_lPersons.begin() + nodeIdx); - - // update indexes - for (unsigned int i = 0; i < d_ptr->m_lPersons.size(); ++i) { - d_ptr->m_lPersons[i]->m_Index = i; - for (unsigned int j = 0; j < d_ptr->m_lPersons[i]->m_lChildren.size(); ++j) - d_ptr->m_lPersons[i]->m_lChildren[j]->m_Index = j; - } - endRemoveRows(); - - //Deprecate the placeholder - if (d_ptr->m_hPlaceholders.contains(item->uid())) { - PersonPlaceHolder* placeholder = d_ptr->m_hPlaceholders[item->uid()]; - if (placeholder) - d_ptr->m_hPlaceholders[item->uid()] = nullptr; - } - break; - } - } - - emit personRemoved(item); - return item; -} - -///When we get a peer profile, its a vCard from a ContactRequest or a Call. We need to verify if -///this is Person which already exists, and so we simply need to update our existing vCard, or if -///this is a new Person, in which case we'll save a new vCard. -///We cannot trust the UID in the vCard for uniqueness. We can only rely on the RingID to be unique. -bool PersonModel::addPeerProfile(Person* person) -{ - if (!person or not person->collection()) return false; - - for (auto col : collections(CollectionInterface::SupportedFeatures::ADD)) { - //Only add profile to peer profile collection - if (col->id() == "ppc") { - col->add(person); - return true; - } - } - return false; -} - -///@deprecated -bool PersonModel::addNewPerson(Person* c, CollectionInterface* backend) -{ - if ((!backend) && (!collections().size())) - return false; - - bool ret = false; - - if (backend) { - ret |= backend->editor<Person>()->addNew(c); - } - else for (CollectionInterface* col :collections(CollectionInterface::SupportedFeatures::ADD)) { - if (col->id() != "trcb") //Do not add to the transitional contact backend - ret |= col->editor<Person>()->addNew(c); - } - - return ret; -} - -void PersonModelPrivate::slotLastUsedTimeChanged(time_t t) const -{ - emit q_ptr->lastUsedTimeChanged(static_cast<Person*>(QObject::sender()), t); -} - - -#include <personmodel.moc> diff --git a/src/personmodel.h b/src/personmodel.h deleted file mode 100644 index 8b547c0da4be352bfc36174f9427c5e2f1761d94..0000000000000000000000000000000000000000 --- a/src/personmodel.h +++ /dev/null @@ -1,95 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QObject> -#include <QHash> -#include <QStringList> -#include <QVariant> -#include <QtCore/QAbstractItemModel> - -#include "typedefs.h" -#include "person.h" -#include "collectionmanagerinterface.h" - -//Ring -class Person; -class Account; -class CollectionInterface; -class PersonModelPrivate; -class PersonItemNode; - -//Typedef -typedef QVector<Person*> PersonList; - -///PersonModel: Allow different way to handle contact without polluting the library -class LIB_EXPORT PersonModel : - public QAbstractItemModel, public CollectionManagerInterface<Person> { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - friend class PersonItemNode; -public: - - template <typename T > using ItemMediator = CollectionMediator<Person>; - - - explicit PersonModel(QObject* parent = nullptr); - virtual ~PersonModel(); - - //Mutator - bool addPeerProfile(Person* c); - - //Getters - Person* getPersonByUid ( const QByteArray& uid ); - Person* getPlaceHolder(const QByteArray& uid ); - - //Model implementation - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual QModelIndex parent ( const QModelIndex& index ) const override; - virtual QModelIndex index ( int row, int column, const QModelIndex& parent=QModelIndex()) const override; - virtual QVariant headerData ( int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Singleton - static PersonModel& instance(); - -private: - QScopedPointer<PersonModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(PersonModel) - - //Backend interface - virtual void collectionAddedCallback(CollectionInterface* backend) override; - virtual bool addItemCallback(const Person* item) override; - virtual bool removeItemCallback(const Person* item) override; - -public Q_SLOTS: - bool addNewPerson(Person* c, CollectionInterface* backend = nullptr); - -Q_SIGNALS: - void personRemoved(const Person* c); - void newPersonAdded(const Person* c); - void newBackendAdded(CollectionInterface* backend); - ///The last time there was an interaction with this person changed - void lastUsedTimeChanged(Person* p, long long) const; -}; diff --git a/src/phonedirectorymodel.cpp b/src/phonedirectorymodel.cpp deleted file mode 100644 index 3ad615416fbfdaf1e894ace2a1f6c3cb6b2652bd..0000000000000000000000000000000000000000 --- a/src/phonedirectorymodel.cpp +++ /dev/null @@ -1,945 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "phonedirectorymodel.h" - -//Qt -#include <QtCore/QCoreApplication> -#include <QtCore/QDateTime> - -//DRing -#include <account_const.h> - -//Ring -#include "contactmethod.h" -#include "call.h" -#include "uri.h" -#include "account.h" -#include "person.h" -#include "accountmodel.h" -#include "numbercategory.h" -#include "numbercategorymodel.h" -#include "collectioninterface.h" -#include "dbus/presencemanager.h" -#include "globalinstances.h" -#include "private/contactmethod_p.h" -#include "interfaces/pixmapmanipulatori.h" -#include "personmodel.h" -#include "dbus/configurationmanager.h" -#include "media/recordingmodel.h" - -//Private -#include "private/phonedirectorymodel_p.h" - -PhoneDirectoryModelPrivate::PhoneDirectoryModelPrivate(PhoneDirectoryModel* parent) : QObject(parent), q_ptr(parent), -m_CallWithAccount(false),m_pPopularModel(nullptr) -{ - connect(&NameDirectory::instance(), &NameDirectory::registeredNameFound, this, &PhoneDirectoryModelPrivate::slotRegisteredNameFound); -} - -PhoneDirectoryModel::PhoneDirectoryModel(QObject* parent) : - QAbstractTableModel(parent?parent:QCoreApplication::instance()), d_ptr(new PhoneDirectoryModelPrivate(this)) -{ - setObjectName("PhoneDirectoryModel"); - connect(&PresenceManager::instance(),SIGNAL(newBuddyNotification(QString,QString,bool,QString)),d_ptr.data(), - SLOT(slotNewBuddySubscription(QString,QString,bool,QString))); -} - -PhoneDirectoryModel::~PhoneDirectoryModel() -{ - QList<NumberWrapper*> vals = d_ptr->m_hNumbersByNames.values(); - //Used by indexes - d_ptr->m_hNumbersByNames.clear(); - d_ptr->m_lSortedNames.clear(); - while (vals.size()) { - NumberWrapper* w = vals[0]; - vals.removeAt(0); - delete w; - } - - //Used by auto completion - vals = d_ptr->m_hSortedNumbers.values(); - d_ptr->m_hSortedNumbers.clear(); - d_ptr->m_hDirectory.clear(); - while (vals.size()) { - NumberWrapper* w = vals[0]; - vals.removeAt(0); - delete w; - } -} - -PhoneDirectoryModel& PhoneDirectoryModel::instance() -{ - static auto instance = new PhoneDirectoryModel; - return *instance; -} - -QHash<int,QByteArray> PhoneDirectoryModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -QVariant PhoneDirectoryModel::data(const QModelIndex& index, int role ) const -{ - if (!index.isValid() || index.row() >= d_ptr->m_lNumbers.size()) return QVariant(); - const ContactMethod* number = d_ptr->m_lNumbers[index.row()]; - switch (static_cast<PhoneDirectoryModelPrivate::Columns>(index.column())) { - case PhoneDirectoryModelPrivate::Columns::URI: - switch (role) { - case Qt::DisplayRole: - return number->uri(); - case Qt::DecorationRole : - return GlobalInstances::pixmapManipulator().decorationRole(number); - case (int) Role::Object: - return QVariant::fromValue(const_cast<ContactMethod*>(number)); - } - break; - case PhoneDirectoryModelPrivate::Columns::TYPE: - switch (role) { - case Qt::DisplayRole: - return number->category()->name(); - case Qt::DecorationRole: - return number->icon(); - } - break; - case PhoneDirectoryModelPrivate::Columns::CONTACT: - switch (role) { - case Qt::DisplayRole: - return number->contact()?number->contact()->formattedName():QVariant(); - } - break; - case PhoneDirectoryModelPrivate::Columns::ACCOUNT: - switch (role) { - case Qt::DisplayRole: - return number->account()?number->account()->id():QVariant(); - } - break; - case PhoneDirectoryModelPrivate::Columns::STATE: - switch (role) { - case Qt::DisplayRole: - return (int)number->type(); - } - break; - case PhoneDirectoryModelPrivate::Columns::CALL_COUNT: - switch (role) { - case Qt::DisplayRole: - return number->callCount(); - } - break; - case PhoneDirectoryModelPrivate::Columns::LAST_USED: - switch (role) { - case Qt::DisplayRole: - return (int)number->lastUsed(); - } - break; - case PhoneDirectoryModelPrivate::Columns::NAME_COUNT: - switch (role) { - case Qt::DisplayRole: - return number->alternativeNames().size(); - break; - case Qt::ToolTipRole: { - QString out = "<table>"; - QHashIterator<QString, QPair<int, time_t>> iter(number->alternativeNames()); - while (iter.hasNext()) { - iter.next(); - out += QString("<tr><td>%1</td><td>%2</td></tr>").arg(iter.value().first).arg(iter.key()); - } - out += "</table>"; - return out; - } - } - break; - case PhoneDirectoryModelPrivate::Columns::TOTAL_SECONDS: - switch (role) { - case Qt::DisplayRole: - return number->totalSpentTime(); - } - break; - case PhoneDirectoryModelPrivate::Columns::WEEK_COUNT: - switch (role) { - case Qt::DisplayRole: - return number->weekCount(); - } - break; - case PhoneDirectoryModelPrivate::Columns::TRIM_COUNT: - switch (role) { - case Qt::DisplayRole: - return number->trimCount(); - } - break; - case PhoneDirectoryModelPrivate::Columns::HAVE_CALLED: - switch (role) { - case Qt::DisplayRole: - return number->haveCalled(); - } - break; - case PhoneDirectoryModelPrivate::Columns::POPULARITY_INDEX: - switch (role) { - case Qt::DisplayRole: - return number->popularityIndex(); - } - break; - case PhoneDirectoryModelPrivate::Columns::BOOKMARED: - switch (role) { - case Qt::CheckStateRole: - return number->isBookmarked()?Qt::Checked:Qt::Unchecked; - } - break; - case PhoneDirectoryModelPrivate::Columns::HAS_CERTIFICATE: - switch (role) { - case Qt::CheckStateRole: - return number->certificate()?Qt::Checked:Qt::Unchecked; - } - break; - case PhoneDirectoryModelPrivate::Columns::TRACKED: - switch (role) { - case Qt::CheckStateRole: - if (number->account() && number->account()->supportPresenceSubscribe()) - return number->isTracked()?Qt::Checked:Qt::Unchecked; - } - break; - case PhoneDirectoryModelPrivate::Columns::PRESENT: - switch (role) { - case Qt::CheckStateRole: - return number->isPresent()?Qt::Checked:Qt::Unchecked; - } - break; - case PhoneDirectoryModelPrivate::Columns::PRESENCE_MESSAGE: - switch (role) { - case Qt::DisplayRole: { - if ((index.column() == static_cast<int>(PhoneDirectoryModelPrivate::Columns::TRACKED) - || static_cast<int>(PhoneDirectoryModelPrivate::Columns::PRESENT)) - && number->account() && (!number->account()->supportPresenceSubscribe())) { - return tr("This account does not support presence tracking"); - } - else if (!number->account()) - return tr("No associated account"); - else - return number->presenceMessage(); - } - } - break; - case PhoneDirectoryModelPrivate::Columns::UID: - switch (role) { - case Qt::DisplayRole: - case Qt::ToolTipRole: - return number->uid(); - } - break; - case PhoneDirectoryModelPrivate::Columns::REGISTERED_NAME: - switch (role) { - case Qt::DisplayRole: - case Qt::ToolTipRole: - return number->registeredName(); - } - break; - } - return QVariant(); -} - -int PhoneDirectoryModel::rowCount(const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : d_ptr->m_lNumbers.size(); -} - -int PhoneDirectoryModel::columnCount(const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : 20; -} - -Qt::ItemFlags PhoneDirectoryModel::flags(const QModelIndex& index ) const -{ - const ContactMethod* number = d_ptr->m_lNumbers[index.row()]; - - // Mark the "old" duplicate as disabled. They are now zombies acting as - // proxies to the real contact methods. - if (number->isDuplicate()) - return Qt::NoItemFlags; - - const bool enabled = !((index.column() == static_cast<int>(PhoneDirectoryModelPrivate::Columns::TRACKED) - || static_cast<int>(PhoneDirectoryModelPrivate::Columns::PRESENT)) - && number->account() && (!number->account()->supportPresenceSubscribe())); - - return Qt::ItemIsEnabled - | Qt::ItemIsSelectable - | (index.column() == static_cast<int>(PhoneDirectoryModelPrivate::Columns::TRACKED)&&enabled?Qt::ItemIsUserCheckable:Qt::NoItemFlags); -} - -///This model is read and for debug purpose -bool PhoneDirectoryModel::setData(const QModelIndex& index, const QVariant &value, int role ) -{ - ContactMethod* number = d_ptr->m_lNumbers[index.row()]; - if (static_cast<PhoneDirectoryModelPrivate::Columns>(index.column())==PhoneDirectoryModelPrivate::Columns::TRACKED) { - if (role == Qt::CheckStateRole && number) { - number->setTracked(value.toBool()); - } - } - return false; -} - -QVariant PhoneDirectoryModel::headerData(int section, Qt::Orientation orientation, int role ) const -{ - Q_UNUSED(section) - Q_UNUSED(orientation) - static const QString headers[] = {tr("URI"), tr("Type"), tr("Person"), tr("Account"), tr("State"), tr("Call count"), tr("Week count"), - tr("Trimester count"), tr("Have Called"), tr("Last used"), tr("Name_count"),tr("Total (in seconds)"), tr("Popularity_index"), - tr("Bookmarked"), tr("Tracked"), tr("Has certificate"), tr("Present"), tr("Presence message"), tr("UID"), tr("Registered name") }; - if (role == Qt::DisplayRole) return headers[section]; - return QVariant(); -} - -/** - * This helper method make sure that number without an account get registered - * correctly with their alternate URIs. In case there is an obvious duplication, - * it will try to merge both numbers. - */ -void PhoneDirectoryModelPrivate::setAccount(ContactMethod* number, Account* account ) { - const URI& strippedUri = number->uri(); - const bool hasAtSign = strippedUri.hasHostname(); - number->setAccount(account); - - if (!hasAtSign) { - const QString extendedUri = strippedUri+'@'+account->hostname(); - NumberWrapper* wrap = m_hDirectory[extendedUri]; - - //Let make sure none is created in the future for nothing - if (!wrap) { - //It won't be a duplicate as none exist for this URI - wrap = new NumberWrapper(); - m_hDirectory [extendedUri] = wrap; - m_hSortedNumbers[extendedUri] = wrap; - wrap->numbers << number; - - } - else { - //After all this, it is possible the number is now a duplicate - foreach(ContactMethod* n, wrap->numbers) { - if (n != number && n->account() && n->account() == number->account()) { - number->merge(n); - } - } - } - wrap->numbers << number; - - } - - // for RingIDs, once we set an account, we should perform (another) name lookup, in case the - // account has a different name server set from the default - if (number->uri().protocolHint() == URI::ProtocolHint::RING) - NameDirectory::instance().lookupAddress(number->account(), QString(), number->uri().userinfo()); -} - -///Add new information to existing numbers and try to merge -ContactMethod* PhoneDirectoryModelPrivate::fillDetails(NumberWrapper* wrap, const URI& strippedUri, Account* account, Person* contact, const QString& type) -{ - //TODO pick the best URI - //TODO the account hostname change corner case - //TODO search for account that has the same hostname as the URI - if (wrap) { - foreach(ContactMethod* number, wrap->numbers) { - - //BEGIN Check if contact can be set - - //Check if the contact is compatible - const bool hasCompatiblePerson = contact && ( - (!number->contact()) - || ( - (number->contact()->uid() == contact->uid()) - && number->contact() != contact - ) - ); - - //Check if the URI match - const bool hasCompatibleURI = hasCompatiblePerson && (number->uri().hasHostname()?( - /* Has hostname */ - strippedUri == number->uri() - /* Something with an hostname can be used with IP2IP */ //TODO support DHT here - || (account && account->isIp2ip()) - ) : ( /* Has no hostname */ - number->account() && number->uri()+'@'+number->account()->hostname() == strippedUri - )); - - //Check if the account is compatible - const bool hasCompatibleAccount = hasCompatibleURI && ((!account) - || (!number->account()) - /* Direct match, this is always valid */ - || (account == number->account()) - /* IP2IP is a special case */ //TODO support DHT here - || ( - account->isIp2ip() - && strippedUri.hasHostname() - )); - - //TODO the Display name could be used to influence the choice - //It would need to ignore all possible translated values of unknown - //and only be available when another information match - - //If everything match, set the contact - if (hasCompatibleAccount) - number->setPerson(contact); - //END Check if the contact can be set - - - //BEGIN Check is account can be set - // Try to match the account - // Not perfect, but better than ignoring the high probabilities - //TODO only do it is hostname match - if ((!account) || account != number->account()) { - - if (account && (!contact) && !number->account()) - setAccount(number,account); - - //Set a type, this has low probabilities of being invalid - if ((!number->hasType()) && (!type.isEmpty())) { - number->setCategory(NumberCategoryModel::instance().getCategory(type)); - } - - //We already have enough information to confirm the choice - if (contact && number->contact() &&((contact->uid()) == number->contact()->uid())) - return number; - } - //END Check is account can be set - } - } - return nullptr; -} - -/** - * This version of getNumber() try to get a phone number with a contact from an URI and account - * It will also try to attach an account to existing numbers. This is not 100% reliable, but - * it is correct often enough to do it. - */ -ContactMethod* PhoneDirectoryModel::getNumber(const QString& uri, Account* account, const QString& type) -{ - return getNumber(uri,nullptr,account,type); -} - - -ContactMethod* PhoneDirectoryModel::getNumber(const QString& uri, const QString& type) -{ - const URI strippedUri(uri); - return getNumber(strippedUri, type); -} - -///Return/create a number when no information is available -ContactMethod* PhoneDirectoryModel::getNumber(const URI& uri, const QString& type) -{ - NumberWrapper* wrap = d_ptr->m_hDirectory[uri]; - if (wrap) { - ContactMethod* nb = wrap->numbers[0]; - if ((!nb->hasType()) && (!type.isEmpty())) { - nb->setCategory(NumberCategoryModel::instance().getCategory(type)); - } - return nb; - } - - //Too bad, lets create one - ContactMethod* number = new ContactMethod(uri, NumberCategoryModel::instance().getCategory(type)); - number->setIndex(d_ptr->m_lNumbers.size()); - d_ptr->m_lNumbers << number; - connect(number,SIGNAL(callAdded(Call*)),d_ptr.data(),SLOT(slotCallAdded(Call*))); - connect(number,SIGNAL(changed()),d_ptr.data(),SLOT(slotChanged())); - connect(number,&ContactMethod::lastUsedChanged,d_ptr.data(), &PhoneDirectoryModelPrivate::slotLastUsedChanged); - connect(number,&ContactMethod::contactChanged ,d_ptr.data(), &PhoneDirectoryModelPrivate::slotContactChanged); - connect(number,&ContactMethod::rebased ,d_ptr.data(), &PhoneDirectoryModelPrivate::slotContactMethodMerged); - - const QString hn = number->uri().hostname(); - - emit layoutChanged(); - if (!wrap) { - wrap = new NumberWrapper(); - d_ptr->m_hDirectory[uri] = wrap; - d_ptr->m_hSortedNumbers[uri] = wrap; - } - wrap->numbers << number; - - // perform a username lookup for new CM with RingID - if (number->uri().protocolHint() == URI::ProtocolHint::RING) - NameDirectory::instance().lookupAddress(number->account(), QString(), number->uri().userinfo()); - - return number; -} - -///Create a number when a more information is available duplicated ones -ContactMethod* PhoneDirectoryModel::getNumber(const QString& uri, Person* contact, Account* account, const QString& type) -{ - //Remove extra data such as "<sip:" from the main URI - const URI strippedUri(uri); - - //See if the number is already loaded - NumberWrapper* wrap = d_ptr->m_hDirectory[strippedUri]; - NumberWrapper* wrap2 = nullptr; - NumberWrapper* wrap3 = nullptr; - - //Check if the URI is complete or short - const bool hasAtSign = strippedUri.hasHostname(); - - //Try to see if there is a better candidate with a suffix (LAN only) - if ( !hasAtSign && account ) { - //Append the account hostname - wrap2 = d_ptr->m_hDirectory[strippedUri+'@'+account->hostname()]; - } - - //Check - ContactMethod* confirmedCandidate = d_ptr->fillDetails(wrap,strippedUri,account,contact,type); - - //URIs can be represented in multiple way, check if a more verbose version - //already exist - ContactMethod* confirmedCandidate2 = nullptr; - - //Try to use a ContactMethod with a contact when possible, work only after the - //contact are loaded - if (confirmedCandidate && confirmedCandidate->contact()) - confirmedCandidate2 = d_ptr->fillDetails(wrap2,strippedUri,account,contact,type); - - ContactMethod* confirmedCandidate3 = nullptr; - - //Else, try to see if the hostname correspond to the account and flush it - //This have to be done after the parent if as the above give "better" - //results. It cannot be merged with wrap2 as this check only work if the - //candidate has an account. - if (hasAtSign && account && strippedUri.hostname() == account->hostname()) { - wrap3 = d_ptr->m_hDirectory[strippedUri.userinfo()]; - if (wrap3) { - foreach(ContactMethod* number, wrap3->numbers) { - if (number->account() == account) { - if (contact && ((!number->contact()) || (contact->uid() == number->contact()->uid()))) - number->setPerson(contact); //TODO Check all cases from fillDetails() - //TODO add alternate URI - confirmedCandidate3 = number; - break; - } - } - } - } - - //If multiple ContactMethod are confirmed, then they are the same, merge them - if (confirmedCandidate3 && (confirmedCandidate || confirmedCandidate2)) { - confirmedCandidate3->merge(confirmedCandidate?confirmedCandidate:confirmedCandidate2); - } - else if (confirmedCandidate && confirmedCandidate2) { - if (confirmedCandidate->contact() && !confirmedCandidate2->contact()) - confirmedCandidate2->merge(confirmedCandidate); - else if (confirmedCandidate2->contact() && !confirmedCandidate->contact()) - confirmedCandidate->merge(confirmedCandidate2); - } - - //Empirical testing resulted in this as the best return order - //The merge may have failed either in the "if" above or in the merging code - if (confirmedCandidate2) - return confirmedCandidate2; - if (confirmedCandidate) - return confirmedCandidate; - if (confirmedCandidate3) - return confirmedCandidate3; - - //No better candidates were found than the original assumption, use it - if (wrap) { - foreach(ContactMethod* number, wrap->numbers) { - if (((!account) || number->account() == account) && ((!contact) || ((*contact) == number->contact()) || (!number->contact()))) { - //Assume this is valid until a smarter solution is implemented to merge both - //For a short time, a placeholder contact and a contact can coexist, drop the placeholder - if (contact && (!number->contact() || (contact->uid() == number->contact()->uid()))) - number->setPerson(contact); - - return number; - } - } - } - - //Create the number - ContactMethod* number = new ContactMethod(strippedUri,NumberCategoryModel::instance().getCategory(type)); - number->setAccount(account); - number->setIndex( d_ptr->m_lNumbers.size()); - if (contact) - number->setPerson(contact); - d_ptr->m_lNumbers << number; - connect(number,SIGNAL(callAdded(Call*)),d_ptr.data(),SLOT(slotCallAdded(Call*))); - connect(number,SIGNAL(changed()),d_ptr.data(),SLOT(slotChanged())); - connect(number,&ContactMethod::lastUsedChanged,d_ptr.data(), &PhoneDirectoryModelPrivate::slotLastUsedChanged); - connect(number,&ContactMethod::contactChanged ,d_ptr.data(), &PhoneDirectoryModelPrivate::slotContactChanged ); - connect(number,&ContactMethod::rebased ,d_ptr.data(), &PhoneDirectoryModelPrivate::slotContactMethodMerged); - if (!wrap) { - wrap = new NumberWrapper(); - d_ptr->m_hDirectory [strippedUri] = wrap; - d_ptr->m_hSortedNumbers[strippedUri] = wrap; - - //Also add its alternative URI, it should be safe to do - if ( !hasAtSign && account && !account->hostname().isEmpty() ) { - const QString extendedUri = strippedUri+'@'+account->hostname(); - //Also check if it hasn't been created by setAccount - if ((!wrap2) && (!d_ptr->m_hDirectory[extendedUri])) { - wrap2 = new NumberWrapper(); - d_ptr->m_hDirectory [extendedUri] = wrap2; - d_ptr->m_hSortedNumbers[extendedUri] = wrap2; - } - - if (wrap2) - wrap2->numbers << number; - else - qWarning() << "PhoneDirectoryModel: code path should not be reached, wrap2 is nullptr"; - } - - } - wrap->numbers << number; - emit layoutChanged(); - - // perform a username lookup for new CM with RingID - if (number->uri().protocolHint() == URI::ProtocolHint::RING) - NameDirectory::instance().lookupAddress(number->account(), QString(), number->uri().userinfo()); - - return number; -} - -ContactMethod* PhoneDirectoryModel::fromTemporary(const TemporaryContactMethod* number) -{ - return getNumber(number->uri(),number->contact(),number->account()); -} - -ContactMethod* PhoneDirectoryModel::fromHash(const QString& hash) -{ - const QStringList fields = hash.split("///"); - if (fields.size() == 3) { - const QString uri = fields[0]; - const QByteArray acc = fields[1].toLatin1(); - Account* account = acc.isEmpty() ? nullptr : AccountModel::instance().getById(acc); - Person* contact = PersonModel::instance().getPersonByUid(fields[2].toUtf8()); - return getNumber(uri,contact,account); - } - else if (fields.size() == 1) { - //FIXME Remove someday, handle version v1.0 to v1.2.3 bookmark format - return getNumber(fields[0]); - } - qDebug() << "Invalid hash" << hash; - return nullptr; -} - - -/** Filter the existing CMs for an URI without flooding the model with merge - * candidates. - * - * This should help reduce the number of accidental duplicates once its - * usage spread over the code. It also reduce the boilerplate code. - **/ -ContactMethod* PhoneDirectoryModel::getExistingNumberIf(const URI& uri, const std::function<bool(const ContactMethod*)>& pred) const -{ - // Prevent the most obvious duplicates - const URI strippedUri(uri); - - //See if the number is already loaded - const NumberWrapper* w = d_ptr->m_hDirectory[strippedUri]; - - if (!w) - return nullptr; - - const auto iter = std::find_if(std::begin(w->numbers), std::end(w->numbers), pred); - - return (iter != std::end(w->numbers)) ? *iter : nullptr; -} - -QVector<ContactMethod*> PhoneDirectoryModel::getNumbersByPopularity() const -{ - return d_ptr->m_lPopularityIndex; -} - -void PhoneDirectoryModelPrivate::slotCallAdded(Call* call) -{ - Q_UNUSED(call) - - if (call->state() == Call::State::FAILURE) - return; //don't update popularity for failed calls - - ContactMethod* number = qobject_cast<ContactMethod*>(sender()); - if (number) { - int currentIndex = number->popularityIndex(); - - //The number is already in the top 10 and just passed the "index-1" one - if (currentIndex > 0 && m_lPopularityIndex[currentIndex-1]->callCount() < number->callCount()) { - do { - ContactMethod* tmp = m_lPopularityIndex[currentIndex-1]; - m_lPopularityIndex[currentIndex-1] = number; - m_lPopularityIndex[currentIndex ] = tmp ; - tmp->setPopularityIndex(tmp->popularityIndex()+1); - currentIndex--; - } while (currentIndex && m_lPopularityIndex[currentIndex-1]->callCount() < number->callCount()); - number->setPopularityIndex(currentIndex); - emit q_ptr->layoutChanged(); - if (m_pPopularModel) - m_pPopularModel->reload(); - } - //The top 10 is not complete, a call count of "1" is enough to make it - else if (m_lPopularityIndex.size() < 10 && currentIndex == -1) { - m_lPopularityIndex << number; - if (m_pPopularModel) - m_pPopularModel->addRow(); - number->setPopularityIndex(m_lPopularityIndex.size()-1); - emit q_ptr->layoutChanged(); - } - //The top 10 is full, but this number just made it to the top 10 - else if (currentIndex == -1 && m_lPopularityIndex.size() >= 10 && m_lPopularityIndex[9] != number && m_lPopularityIndex[9]->callCount() < number->callCount()) { - ContactMethod* tmp = m_lPopularityIndex[9]; - tmp->setPopularityIndex(-1); - m_lPopularityIndex[9] = number; - number->setPopularityIndex(9); - emit tmp->changed(); - emit number->changed(); - if (m_pPopularModel) - m_pPopularModel->reload(); - } - - //Now check for new peer names - if (!call->peerName().isEmpty()) { - number->incrementAlternativeName(call->peerName(), call->startTimeStamp()); - } - } -} - -void PhoneDirectoryModelPrivate::slotChanged() -{ - ContactMethod* number = qobject_cast<ContactMethod*>(sender()); - if (number) { - const int idx = number->index(); -#ifndef NDEBUG - if (idx<0) - qDebug() << "Invalid slotChanged() index!" << idx; -#endif - emit q_ptr->dataChanged(q_ptr->index(idx,0),q_ptr->index(idx,static_cast<int>(Columns::REGISTERED_NAME))); - } -} - -/// Remove -void PhoneDirectoryModelPrivate::slotContactMethodMerged(ContactMethod* other) -{ - // Other == cm when the person they depend on got merged. As a CM is an - // "person-lite" this still counts as most code paths care about both. Not - // this, so lets ignore the merged persons. - auto cm = qobject_cast<ContactMethod*>(sender()); - if (other != cm) - emit q_ptr->contactMethodMerged(cm, other); -} - -void PhoneDirectoryModelPrivate::slotLastUsedChanged(time_t t) -{ - ContactMethod* cm = qobject_cast<ContactMethod*>(QObject::sender()); - - if (cm) - emit q_ptr->lastUsedChanged(cm, t); -} - -void PhoneDirectoryModelPrivate::slotContactChanged(Person* newContact, Person* oldContact) -{ - ContactMethod* cm = qobject_cast<ContactMethod*>(QObject::sender()); - - if (cm) - emit q_ptr->contactChanged(cm, newContact, oldContact); -} - -void PhoneDirectoryModelPrivate::slotNewBuddySubscription(const QString& accountId, const QString& uri, bool status, const QString& message) -{ - ContactMethod* number = q_ptr->getNumber(uri,AccountModel::instance().getById(accountId.toLatin1())); - number->setPresent(status); - number->setPresenceMessage(message); - emit number->changed(); -} - -///Make sure the indexes are still valid for those names -void PhoneDirectoryModelPrivate::indexNumber(ContactMethod* number, const QStringList &names) -{ - foreach(const QString& name, names) { - const QString lower = name.toLower(); - const QStringList split = lower.split(' '); - if (split.size() > 1) { - foreach(const QString& chunk, split) { - NumberWrapper* wrap = m_hNumbersByNames[chunk]; - if (!wrap) { - wrap = new NumberWrapper(); - m_hNumbersByNames[chunk] = wrap; - m_lSortedNames[chunk] = wrap; - } - const int numCount = wrap->numbers.size(); - if (!((numCount == 1 && wrap->numbers[0] == number) || (numCount > 1 && wrap->numbers.indexOf(number) != -1))) - wrap->numbers << number; - } - } - NumberWrapper* wrap = m_hNumbersByNames[lower]; - if (!wrap) { - wrap = new NumberWrapper(); - m_hNumbersByNames[lower] = wrap; - m_lSortedNames[lower] = wrap; - } - const int numCount = wrap->numbers.size(); - if (!((numCount == 1 && wrap->numbers[0] == number) || (numCount > 1 && wrap->numbers.indexOf(number) != -1))) - wrap->numbers << number; - } -} - -void -PhoneDirectoryModelPrivate::slotRegisteredNameFound(const Account* account, NameDirectory::LookupStatus status, const QString& address, const QString& name) -{ - if (status != NameDirectory::LookupStatus::SUCCESS) { - // unsuccessful lookup, so its useless - return; - } - if (address.isEmpty() || name.isEmpty()) { - qDebug() << "registered name address (" << address << ") or name (" << name << ") is empty"; - return; - } - - // update relevant contact methods - const URI strippedUri(address); - - //See if the number is already loaded - auto wrap = m_hDirectory.value(strippedUri); - - if (wrap) { - foreach (ContactMethod* cm, wrap->numbers) { - if (cm->account() == account) { - cm->incrementAlternativeName(name, QDateTime::currentDateTime().toTime_t()); - cm->d_ptr->setRegisteredName(name); - - // Add the CM to the directory using the registered name too. - // Note that in theory the wrapper can exist already if the - // user was either offline in a call attempt or if there is a - // collision with a SIP account. - if (!m_hDirectory.contains(name)) { - //TODO support multiple name service, use proper URIs for names - auto wrap2 = new NumberWrapper(); - m_hDirectory [name] = wrap2; - m_hSortedNumbers[name] = wrap2; - wrap2->numbers << cm; - } - else { - auto wrapper = m_hDirectory.value(name); - // Merge the existing CMs now that it is known that the RingId match the username - foreach(ContactMethod* n, wrapper->numbers) { - - // If the account is the same and (as we know) it is a registered name - // there is 100% porbability of match - const bool compAccount = n->account() && - n->account() == cm->account(); - - // Less certain, but close enough. We have a contact with a phone - // number corresponding with a registeredName and `ring:` in front. - // it *could* use a different name service. Anyway, for now this - // isn't widespread enough to care. - const bool compContact = (!n->account()) && n->contact() && - n->uri().schemeType() == URI::SchemeType::RING; - - if (n != cm && (compAccount || compContact)) { - n->merge(cm); - } - } - } - - // Only add it once - if (!m_hDirectory[name]->numbers.indexOf(cm)) { - //TODO check if some deduplication can be performed - m_hDirectory[name]->numbers << cm; - } - } else { - qDebug() << "registered name: uri matches but not account" << name << address << account << cm->account(); - } - } - } else { - // got a registered name for a CM which hasn't been created yet - // This can be left as-is to save memory. Those CMs are never freed. - // It is generally preferred to create as little as possible. - } -} - -int PhoneDirectoryModel::count() const { - return d_ptr->m_lNumbers.size(); -} -bool PhoneDirectoryModel::callWithAccount() const { - return d_ptr->m_CallWithAccount; -} - -//Setters -void PhoneDirectoryModel::setCallWithAccount(bool value) { - d_ptr->m_CallWithAccount = value; -} - -///Popular number model related code - -MostPopularNumberModel::MostPopularNumberModel() : QAbstractListModel(&PhoneDirectoryModel::instance()) { - setObjectName("MostPopularNumberModel"); -} - -QVariant MostPopularNumberModel::data( const QModelIndex& index, int role ) const -{ - if (!index.isValid()) - return QVariant(); - - return PhoneDirectoryModel::instance().d_ptr->m_lPopularityIndex[index.row()]->roleData( - role == Qt::DisplayRole ? (int)Call::Role::Name : role - ); -} - -int MostPopularNumberModel::rowCount( const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : PhoneDirectoryModel::instance().d_ptr->m_lPopularityIndex.size(); -} - -Qt::ItemFlags MostPopularNumberModel::flags( const QModelIndex& index ) const -{ - return index.isValid() ? Qt::ItemIsEnabled | Qt::ItemIsSelectable : Qt::NoItemFlags; -} - -bool MostPopularNumberModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -void MostPopularNumberModel::addRow() -{ - const int oldSize = PhoneDirectoryModel::instance().d_ptr->m_lPopularityIndex.size()-1; - beginInsertRows(QModelIndex(),oldSize,oldSize); - endInsertRows(); -} - -void MostPopularNumberModel::reload() -{ - emit dataChanged(index(0,0),index(rowCount(),0)); -} - -QAbstractListModel* PhoneDirectoryModel::mostPopularNumberModel() const -{ - if (!d_ptr->m_pPopularModel) - d_ptr->m_pPopularModel = new MostPopularNumberModel(); - - return d_ptr->m_pPopularModel; -} - -/** - * @return true if any ContactMethod stored has an unread message. False otherwise - */ -bool -PhoneDirectoryModel::hasUnreadMessage() const -{ - return false; -} - -#include <phonedirectorymodel.moc> diff --git a/src/phonedirectorymodel.h b/src/phonedirectorymodel.h deleted file mode 100644 index 85b0c05ad36dc7b145610108a0b5cd364e869121..0000000000000000000000000000000000000000 --- a/src/phonedirectorymodel.h +++ /dev/null @@ -1,112 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" - -// STD -#include <functional> - -//Qt -#include <QtCore/QString> -#include <QtCore/QAbstractTableModel> - -//Ring -#include "uri.h" -class ContactMethod ; -class Person ; -class Account ; -class Call ; -class TemporaryContactMethod; -class NumberTreeBackend; - -//Private -class PhoneDirectoryModelPrivate; - -///PhoneDirectoryModel: A model for account phonedirectory -class LIB_EXPORT PhoneDirectoryModel : public QAbstractTableModel { - - friend class MostPopularNumberModel; - - //Friend unit test class - friend class AutoCompletionTest; - - //Phone number need to update the indexes as they change - friend class ContactMethod; - - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop -public: - Q_PROPERTY(int count READ count ) - - enum class Role { - Object = 100, - }; - - virtual ~PhoneDirectoryModel(); - - //Abstract model members - virtual QVariant data (const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount (const QModelIndex& parent = QModelIndex() ) const override; - virtual int columnCount(const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags (const QModelIndex& index ) const override; - virtual bool setData (const QModelIndex& index, const QVariant &value, int role ) override; - virtual QVariant headerData (int section, Qt::Orientation orientation, int role = Qt::DisplayRole ) const override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Singleton - static PhoneDirectoryModel& instance(); - - //Factory - Q_INVOKABLE ContactMethod* getNumber(const QString& uri, const QString& type = QString()); - Q_INVOKABLE ContactMethod* getNumber(const URI& uri, const QString& type = QString()); - Q_INVOKABLE ContactMethod* getNumber(const QString& uri, Account* account, const QString& type = QString()); - Q_INVOKABLE ContactMethod* getNumber(const QString& uri, Person* contact, Account* account = nullptr, const QString& type = QString()); - Q_INVOKABLE ContactMethod* fromHash (const QString& hash); - Q_INVOKABLE ContactMethod* fromTemporary(const TemporaryContactMethod* number); - - ContactMethod* getExistingNumberIf(const URI& uri, const std::function<bool(const ContactMethod*)>& pred) const; - - //Getter - int count() const; - bool callWithAccount() const; - QAbstractListModel* mostPopularNumberModel() const; - bool hasUnreadMessage() const; - - //Setters - void setCallWithAccount(bool value); - - //Static - QVector<ContactMethod*> getNumbersByPopularity() const; - -private: - //Constructor - explicit PhoneDirectoryModel(QObject* parent = nullptr); - - //Attributes - QScopedPointer<PhoneDirectoryModelPrivate> d_ptr; - Q_DECLARE_PRIVATE(PhoneDirectoryModel) - -Q_SIGNALS: - void lastUsedChanged(ContactMethod* cm, time_t t); - void contactChanged(ContactMethod* cm, Person* newContact, Person* oldContact); - void contactMethodMerged(ContactMethod* cm, ContactMethod* into); -}; -Q_DECLARE_METATYPE(PhoneDirectoryModel*) diff --git a/src/pixmapmanipulatordefault.cpp b/src/pixmapmanipulatordefault.cpp index 3a79bcaa32d31069f3d4d80ee6b89707ce96c0d6..ee27ca7850e392e8fe2fb5a92f72ddb71dac86bb 100644 --- a/src/pixmapmanipulatordefault.cpp +++ b/src/pixmapmanipulatordefault.cpp @@ -28,14 +28,6 @@ namespace Interfaces { -QVariant PixmapManipulatorDefault::contactPhoto(Person* c, const QSize& size, bool displayPresence) -{ - Q_UNUSED(c) - Q_UNUSED(size) - Q_UNUSED(displayPresence) - return QVariant(); -} - QVariant PixmapManipulatorDefault::numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence, bool isPresent) { Q_UNUSED(p) @@ -45,22 +37,6 @@ QVariant PixmapManipulatorDefault::numberCategoryIcon(const QVariant& p, const Q return QVariant(); } -QVariant PixmapManipulatorDefault::callPhoto(Call* c, const QSize& size, bool displayPresence) -{ - Q_UNUSED(c) - Q_UNUSED(size) - Q_UNUSED(displayPresence) - return QVariant(); -} - -QVariant PixmapManipulatorDefault::callPhoto(const ContactMethod* c, const QSize& size, bool displayPresence) -{ - Q_UNUSED(c) - Q_UNUSED(size) - Q_UNUSED(displayPresence) - return QVariant(); -} - QVariant PixmapManipulatorDefault::conversationPhoto(const lrc::api::conversation::Info& conversation, const lrc::api::account::Info& accountInfo, @@ -74,12 +50,6 @@ PixmapManipulatorDefault::conversationPhoto(const lrc::api::conversation::Info& return QVariant(); } -QVariant PixmapManipulatorDefault::securityIssueIcon(const QModelIndex& index) -{ - Q_UNUSED(index) - return QVariant(); -} - QByteArray PixmapManipulatorDefault::toByteArray(const QVariant& pxm) { Q_UNUSED(pxm) @@ -99,49 +69,12 @@ QVariant PixmapManipulatorDefault::userActionIcon(const UserActionElement& state return QVariant(); } -QVariant PixmapManipulatorDefault::collectionIcon(const CollectionInterface* interface, PixmapManipulatorI::CollectionIconHint hint) const -{ - Q_UNUSED(interface) - Q_UNUSED(hint) - return QVariant(); -} - -QVariant PixmapManipulatorDefault::securityLevelIcon(const SecurityEvaluationModel::SecurityLevel level) const -{ - Q_UNUSED(level) - return QVariant(); -} - QVariant PixmapManipulatorDefault::decorationRole(const QModelIndex& index) { Q_UNUSED(index) return QVariant(); } -QVariant PixmapManipulatorDefault::decorationRole(const Call* c) -{ - Q_UNUSED(c) - return QVariant(); -} - -QVariant PixmapManipulatorDefault::decorationRole(const ContactMethod* cm) -{ - Q_UNUSED(cm) - return QVariant(); -} - -QVariant PixmapManipulatorDefault::decorationRole(const Person* p) -{ - Q_UNUSED(p) - return QVariant(); -} - -QVariant PixmapManipulatorDefault::decorationRole(const Account* acc) -{ - Q_UNUSED(acc) - return QVariant(); -} - QVariant PixmapManipulatorDefault::decorationRole(const lrc::api::conversation::Info& conversation, const lrc::api::account::Info& accountInfo) diff --git a/src/pixmapmanipulatordefault.h b/src/pixmapmanipulatordefault.h index 1b957d167fd8996213806aefea85a947a5a1c396..81519f682e5908f7e0ecd1747b4a728c89f9e3ba 100644 --- a/src/pixmapmanipulatordefault.h +++ b/src/pixmapmanipulatordefault.h @@ -24,26 +24,16 @@ namespace Interfaces { ///Default implementation of the PixmapManipulator interface which simply returns empty QVariants/QByteArrays class LIB_EXPORT PixmapManipulatorDefault : public PixmapManipulatorI { public: - QVariant contactPhoto(Person* c, const QSize& size, bool displayPresence = true) override; - QVariant callPhoto(Call* c, const QSize& size, bool displayPresence = true) override; QVariant conversationPhoto(const lrc::api::conversation::Info& conversation, const lrc::api::account::Info& accountInfo, const QSize& size, bool displayPresence = true) override; - QVariant callPhoto(const ContactMethod* n, const QSize& size, bool displayPresence = true) override; QVariant numberCategoryIcon(const QVariant& p, const QSize& size, bool displayPresence = false, bool isPresent = false) override; - QVariant securityIssueIcon(const QModelIndex& index) override; QByteArray toByteArray(const QVariant& pxm) override; QVariant personPhoto(const QByteArray& data, const QString& type = "PNG") override; - QVariant collectionIcon(const CollectionInterface* interface, PixmapManipulatorI::CollectionIconHint hint = PixmapManipulatorI::CollectionIconHint::NONE) const override; - QVariant securityLevelIcon(const SecurityEvaluationModel::SecurityLevel level) const override; QVariant decorationRole(const QModelIndex& index) override; - QVariant decorationRole(const Call* c ) override; - QVariant decorationRole(const ContactMethod* cm ) override; - QVariant decorationRole(const Person* p ) override; QVariant decorationRole(const lrc::api::conversation::Info& conversation, const lrc::api::account::Info& accountInfo) override; - QVariant decorationRole(const Account* acc ) override; /** * Return the icons associated with the action and its state */ diff --git a/src/private/account_p.h b/src/private/account_p.h deleted file mode 100644 index f87b48354ed980870deb014f32e61a0257a1b586..0000000000000000000000000000000000000000 --- a/src/private/account_p.h +++ /dev/null @@ -1,120 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QObject> -#include <QtCore/QHash> - -//Ring -#include <account.h> -#include <private/matrixutils.h> - -class AccountPrivate; -class ContactMethod; -class Profile; - -typedef void (AccountPrivate::*account_function)(); - -class AccountPrivate final : public QObject -{ -public: - Q_OBJECT - Q_DECLARE_PUBLIC(Account) - - class RegistrationEnabled { - public: - constexpr static const char* YES = "true"; - constexpr static const char* NO = "false"; - }; - - friend class AccountPlaceHolder; - - //Constructor - explicit AccountPrivate(Account* acc); - - //Attributes - QByteArray m_AccountId ; - QHash<QString,QString> m_hAccountDetails ; - ContactMethod* m_pAccountNumber ; - Account* q_ptr ; - bool m_isLoaded ; - int m_LastTransportCode ; - QString m_LastTransportMessage ; - Account::RegistrationState m_RegistrationState ; - QString m_LastSipRegistrationStatus; - unsigned short m_UseDefaultPort ; - bool m_RemoteEnabledState ; - uint m_InternalId ; - - //Setters - void setAccountProperties(const QHash<QString,QString>& m ); - bool setAccountProperty (const QString& param, const QString& val ); - - //Getters - QString accountDetail(const QString& param) const; - - //Mutator - bool merge(Account* account); - - //Helpers - inline void changeState(Account::EditState state); - bool updateState(); - void regenSecurityValidation(); - - //State actions - void performAction(Account::EditAction action); - void nothing(); - void edit (); - void modify (); - void remove (); - void cancel (); - void outdate(); - void reload (); - void save (); - void reloadMod() {reload();modify();} - - KeyExchangeModel* m_pKeyExchangeModel ; - SecurityEvaluationModel* m_pSecurityEvaluationModel ; - QAbstractItemModel* m_pKnownCertificates ; - QAbstractItemModel* m_pBannedCertificates ; - QAbstractItemModel* m_pAllowedCertificates ; - Account::EditState m_CurrentState ; - QMetaObject::Connection m_cTlsCert ; - QMetaObject::Connection m_cTlsCaCert ; - Profile* m_pProfile {nullptr} ; - Account::ContactMethods m_NumbersFromDaemon ; - - QHash<int, Account::RoleStatus> m_hRoleStatus; - - // State machines - static const Matrix2D<Account::EditState, Account::EditAction, account_function> stateMachineActionsOnState; - - //Cached account details (as they are called too often for the hash) - mutable QString m_HostName; - mutable QString m_LastErrorMessage; - mutable int m_LastErrorCode; - mutable int m_VoiceMailCount; - mutable Certificate* m_pCaCert; - mutable Certificate* m_pTlsCert; - -public Q_SLOTS: - void slotPresentChanged (bool present ); - void slotPresenceMessageChanged(const QString& ); - void slotUpdateCertificate ( ); -}; diff --git a/src/private/accountmodel_p.h b/src/private/accountmodel_p.h deleted file mode 100644 index 136a1762033b138054bb2fff858569d447c94663..0000000000000000000000000000000000000000 --- a/src/private/accountmodel_p.h +++ /dev/null @@ -1,75 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * Nicolas Jäger <nicolas.jager@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QObject> -#include <QtCore/QStringList> - -//Ring -#include <account.h> -#include <accountmodel.h> -#include "matrixutils.h" -class AccountModel; -class QItemSelectionModel; - -class AccountModelPrivate final : public QObject -{ - Q_OBJECT - Q_DECLARE_PUBLIC(AccountModel) - -public: - //Constructor - explicit AccountModelPrivate(AccountModel* parent); - void init(); - - //Helpers - void enableProtocol(Account::Protocol proto); - AccountModel::EditState convertAccountEditState(const Account::EditState s); - void insertAccount(Account* a, int idx); - void removeAccount(Account* account); - - //Attributes - AccountModel* q_ptr ; - QVector<Account*> m_lAccounts ; - QStringList m_lDeletedAccounts ; - Account* m_pIP2IP ; - QList<Account*> m_pRemovedAccounts ; - QItemSelectionModel* m_pSelectionModel ; - QItemSelectionModel* m_pUserSelectionModel {nullptr}; - QStringList m_lMimes ; - QList<Account*> m_lSipAccounts ; - QList<Account*> m_lRingAccounts ; - Matrix1D<Account::Protocol, bool> m_lSupportedProtocols; - - //Future account cache - static QHash<QByteArray,AccountPlaceHolder*> m_hsPlaceHolder; - -public Q_SLOTS: - void slotDaemonAccountChanged(const QString& account, const QString& registration_state, unsigned code, const QString& status); - void slotAccountChanged(Account* a); - void slotSupportedProtocolsChanged(); - void slotVoiceMailNotify( const QString& accountID , int count ); - void slotAccountPresenceEnabledChanged(bool state); - void slotVolatileAccountDetailsChange(const QString& accountId, const MapStringString& details); - void slotExportOnRingEnded(const QString& accountId, int status, const QString& pin); - void slotMigrationEnded(const QString& accountId, const QString& result); - void slotContactAdded(const QString &accountID, const QString &uri, bool confirmed); - void slotContactRemoved(const QString &accountID, const QString &uri, bool banned); -}; diff --git a/src/private/call_p.h b/src/private/call_p.h deleted file mode 100644 index c15ace4b351a1f857b45dd9289636bbef06f1155..0000000000000000000000000000000000000000 --- a/src/private/call_p.h +++ /dev/null @@ -1,264 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -// Std -#include <memory> - -//Qt -#include <QtCore/QObject> - -// Ring -#include "call.h" -#include "private/matrixutils.h" - -//Qt -class QTimer; - -//Ring -class Account; -class ContactMethod; -class InstantMessagingModel; -class Certificate; - -class CallPrivate; -typedef void (CallPrivate::*function)(); - -namespace media { - class Media; - class Recording; -} - -class CallPrivate final : public QObject -{ - Q_OBJECT -public: - friend class Call; - - ///@class ConferenceStateChange Possible values from "conferencechanged" signal - class ConferenceStateChange { - public: - constexpr static const char* HOLD = "HOLD" ; - constexpr static const char* ACTIVE = "ACTIVE_ATTACHED"; - constexpr static const char* DETACHED = "ACTIVE_DETACHED"; - }; - - class StateChange { - public: - constexpr static const char* HUNG_UP = "HUNGUP" ; - constexpr static const char* CONNECTING = "CONNECTING"; - constexpr static const char* RINGING = "RINGING"; - constexpr static const char* INCOMING = "INCOMING"; - constexpr static const char* CURRENT = "CURRENT"; - constexpr static const char* HOLD = "HOLD" ; - constexpr static const char* BUSY = "BUSY" ; - constexpr static const char* FAILURE = "FAILURE"; - constexpr static const char* UNHOLD_CURRENT = "UNHOLD" ; - constexpr static const char* INACTIVE = "INACTIVE"; - constexpr static const char* OVER = "OVER"; - }; - - ///"getConferenceDetails()" fields - class ConfDetailsMapFields { - public: - constexpr static const char* CONF_STATE = "CONF_STATE" ; - constexpr static const char* CONFID = "CONFID" ; - }; - - ///If the call is incoming or outgoing - class CallDirection { - public: - constexpr static const char* INCOMING = "0"; - constexpr static const char* OUTGOING = "1"; - }; - - /** @enum DaemonState - * This enum have all the states a call can take for the daemon. - */ - enum class DaemonState : unsigned int - { - RINGING = 0, /*!< Ringing outgoing or incoming call */ - CONNECTING, /*!< Call connection progressing */ - CURRENT, /*!< Call to which the user can speak and hear */ - BUSY, /*!< Call is busy */ - HOLD, /*!< Call is on hold */ - HUNG_UP, /*!< Call is over */ - FAILURE, /*!< Call has failed */ - OVER, /*!< Call is over */ - INACTIVE, /*!< The call exist, but is not ready */ - COUNT__, - }; - - explicit CallPrivate(Call* parent); - virtual ~CallPrivate(); - - //Attributes - Account* m_Account ; - QString m_DringId ; - ContactMethod* m_pPeerContactMethod; - QString m_PeerName ; - time_t m_pStartTimeStamp ; - time_t m_pStopTimeStamp ; - Call::State m_CurrentState ; - QTimer* m_pTimer ; - bool m_History ; - bool m_Missed ; - Call::Direction m_Direction ; - Call::Type m_Type ; - Certificate* m_pCertificate ; - FlagPack<Call::HoldFlags> m_fHoldFlags ; - Call* m_pParentCall {nullptr}; - QDateTime* m_pDateTime {nullptr}; - QDate* m_pDateOnly {nullptr}; - QString m_FormattedDate ; - - //State machine - /** - * actionPerformedStateMap[orig_state][action] - * Map of the states to go to when the action action is - * performed on a call in state orig_state. - **/ - static const TypedStateMachine< TypedStateMachine< Call::State , Call::Action > , Call::State > actionPerformedStateMap; - - /** - * actionPerformedFunctionMap[orig_state][action] - * Map of the functions to call when the action action is - * performed on a call in state orig_state. - **/ - static const TypedStateMachine< TypedStateMachine< function , Call::Action > , Call::State > actionPerformedFunctionMap; - - /** - * stateChangedStateMap[orig_state][daemon_new_state] - * Map of the states to go to when the daemon sends the signal - * callStateChanged with arg daemon_new_state - * on a call in state orig_state. - **/ - static const TypedStateMachine< TypedStateMachine< Call::State , DaemonState > , Call::State > stateChangedStateMap; - - /** - * stateChangedFunctionMap[orig_state][daemon_new_state] - * Map of the functions to call when the daemon sends the signal - * callStateChanged with arg daemon_new_state - * on a call in state orig_state. - **/ - static const TypedStateMachine< TypedStateMachine< function , DaemonState > , Call::State > stateChangedFunctionMap; - - /** - * metaStateTransitionValidationMap help validate if a state transition violate the lifecycle logic. - * it should technically never happen, but this is an easy additional safety to implement - * and prevent human (developer) errors. - */ - static const TypedStateMachine< TypedStateMachine< bool , Call::LifeCycleState > , Call::State > metaStateTransitionValidationMap; - - /** - * Convert the call state into its meta state (life cycle state). The meta state is a flat, - * forward only progression from creating to archiving of a call. - */ - static const TypedStateMachine< Call::LifeCycleState , Call::State > metaStateMap; - - Matrix2D<media::Media::Type, media::Media::Direction, QList<media::Media*>* > m_mMedias; - - Matrix2D<media::Media::Type, media::Media::Direction, QList<media::Recording*>* > m_mRecordings; - - Matrix2D<media::Media::Type, media::Media::Direction, bool > m_mIsRecording; - - static const Matrix1D<Call::LifeCycleState,function> m_mLifeCycleStateChanges; - - static Call* buildHistoryCall (const QMap<QString,QString>& hc); - - static DaemonState toDaemonCallState (const QString& stateName); - static Call::State confStatetoCallState(const QString& stateName); - Call::State stateChanged(const QString & newState); - void performAction(Call::State previousState, Call::Action action); - void performActionCallback(Call::State previousState, Call::Action action); - - //Automate functions - // See actionPerformedFunctionMap and stateChangedFunctionMap - // to know when it is called. - void nothing () __attribute__ ((const)); - void error () __attribute__ ((noreturn)); - void failure (); - void accept (); - void refuse (); - void acceptTransf (); - void acceptHold (); - void hangUp (); - void cancel (); - void hold (); - void call (); - void transfer (); - void unhold (); - void toggleAudioRecord (); - void toggleVideoRecord (); - void start (); - void startStop (); - void stop (); - void startWeird (); - void warning (); - void remove (); - void abort (); - void sendProfile (); - - //LifeCycleState change callback - void initMedia(); - void terminateMedia(); - - //Helpers - void changeCurrentState(Call::State newState); - void setStartTimeStamp(time_t stamp); - void setStartTimeStamp(); // this version set stamp to current time - void initTimer(); - void registerRenderer(Video::Renderer* renderer); - void removeRenderer(Video::Renderer* renderer); - void setRecordingPath(const QString& path); - static MapStringString getCallDetailsCommon(const QString& callId); - void peerHoldChanged(bool onPeerHold); - template<typename T> - T* mediaFactory(media::Media::Direction dir); - void updateOutgoingMedia(const MapStringString& details); - - //Static getters - static Call::State startStateFromDaemonCallState ( const QString& daemonCallState, const QString& daemonCallType ); - - //Constructor - static Call* buildDialingCall (const QString & peerName, Account* account = nullptr, Call* parent = nullptr ); - static Call* buildIncomingCall (const QString& callId ); - static Call* buildExistingCall (const QString& callId ); - -private: - Call* q_ptr; - - //Constructor helper - static Call* buildCall(const QString& callId, Call::Direction callDirection, Call::State startState); - - //Destructor helper (~Call is private, CallPrivate is a friend class) - static void deleteCall(Call* call); - - // Used as contact until m_pPeerContactMethod is created - // Owner is PhoneDirectoryModel instance - TemporaryContactMethod* m_pDialNumber; - - // Owner is PhoneDirectoryModel instance - TemporaryContactMethod* m_pTransferNumber; - -private Q_SLOTS: - void refuseAfterFailure(); - void updated(); - void videoStopped(); -}; diff --git a/src/private/certificate_p.h b/src/private/certificate_p.h deleted file mode 100644 index f5fe05fdac8a82a25070a3008ca26a20def102d7..0000000000000000000000000000000000000000 --- a/src/private/certificate_p.h +++ /dev/null @@ -1,141 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QDateTime> - -//Ring -#include <securityevaluationmodel.h> - -/** - * Certificates can be loaded either from disk or directly from the - * network sockets. In that case, they don't (always) need to be saved - */ -enum class LoadingType { - FROM_PATH, - FROM_ID -}; - -class DetailsCache { -public: - DetailsCache(const MapStringString& details); - - QDateTime m_ExpirationDate ; - QDateTime m_ActivationDate ; - bool m_RequirePrivateKeyPassword ; - QByteArray m_PublicSignature ; - int m_VersionNumber ; - QByteArray m_SerialNumber ; - QString m_Issuer ; - QByteArray m_SubjectKeyAlgorithm ; - QString m_Cn ; - QString m_N ; - QString m_O ; - QByteArray m_SignatureAlgorithm ; - QByteArray m_Md5Fingerprint ; - QByteArray m_Sha1Fingerprint ; - QByteArray m_PublicKeyId ; - QByteArray m_IssuerDn ; - QDateTime m_NextExpectedUpdateDate ; - QString m_OutgoingServer ; - -}; - -class ChecksCache { -public: - ChecksCache(const MapStringString& checks); - - Certificate::CheckValues m_HasPrivateKey ; - Certificate::CheckValues m_IsExpired ; - Certificate::CheckValues m_HasStrongSigning ; - Certificate::CheckValues m_IsSelfSigned ; - Certificate::CheckValues m_PrivateKeyMatch ; - Certificate::CheckValues m_ArePrivateKeyStoragePermissionOk ; - Certificate::CheckValues m_ArePublicKeyStoragePermissionOk ; - Certificate::CheckValues m_ArePrivateKeyDirectoryPermissionsOk ; - Certificate::CheckValues m_ArePublicKeyDirectoryPermissionsOk ; - Certificate::CheckValues m_ArePrivateKeyStorageLocationOk ; - Certificate::CheckValues m_ArePublicKeyStorageLocationOk ; - Certificate::CheckValues m_ArePrivateKeySelinuxAttributesOk ; - Certificate::CheckValues m_ArePublicKeySelinuxAttributesOk ; - Certificate::CheckValues m_Exist ; - Certificate::CheckValues m_IsValid ; - Certificate::CheckValues m_ValidAuthority ; - Certificate::CheckValues m_HasKnownAuthority ; - Certificate::CheckValues m_IsNotRevoked ; - Certificate::CheckValues m_AuthorityMismatch ; - Certificate::CheckValues m_UnexpectedOwner ; - Certificate::CheckValues m_NotActivated ; -}; - -class CertificatePrivate -{ -public: - //Types - typedef Certificate::CheckValues (Certificate::*accessor)(); - - //Constructor - CertificatePrivate(Certificate* parent, LoadingType _ltype); - ~CertificatePrivate(); - - //Attributes - QString m_Path ; - Certificate::Type m_Type {Certificate::Type::NONE}; - QByteArray m_Content ; - LoadingType m_LoadingType ; - QByteArray m_Id ; - quint64 m_Statuses [3]; - QString m_PrivateKey ; - QString m_PrivateKeyPassword ; - bool m_RequirePrivateKey ; - bool m_RequireStrictPermissions; - Certificate* m_pSignedBy ; - QAbstractItemModel* m_pSeverityProxy ; - ChainOfTrustModel* m_pChainOfTrust ; - FlagPack<Certificate::OriginHint> m_fHints ; - ContactMethod* m_pContactMethod ; - - //Caching - /* The certificate doesn't handle the security evaluation. This is - * SecurityEvaluationModel job. However, it sill have to be kept - * somewhere or it will be recomputed every time ::data() is called on - * a model. - */ - mutable SecurityEvaluationModel::SecurityLevel m_SecurityLevelWithPriv {SecurityEvaluationModel::SecurityLevel::NONE}; - mutable SecurityEvaluationModel::SecurityLevel m_SecurityLevelWithoutPriv {SecurityEvaluationModel::SecurityLevel::NONE}; - bool m_hasLoadedSecurityLevel {false}; - - mutable DetailsCache* m_pDetailsCache; - mutable ChecksCache* m_pCheckCache ; - - //Helpers - void loadDetails(bool reload = false); - void loadChecks (bool loadChecks = false); - - static Matrix1D<Certificate::Checks ,QString> m_slChecksName; - static Matrix1D<Certificate::Checks ,QString> m_slChecksDescription; - static Matrix1D<Certificate::Details,QString> m_slDetailssName; - static Matrix1D<Certificate::Details,QString> m_slDetailssDescription; - - static Certificate::CheckValues toBool(const QString& string); - -private: - Certificate* q_ptr; -}; - diff --git a/src/private/certificatemodel_p.h b/src/private/certificatemodel_p.h deleted file mode 100644 index 712affc39521c0e401f5e38c73782c33d81ed1e0..0000000000000000000000000000000000000000 --- a/src/private/certificatemodel_p.h +++ /dev/null @@ -1,82 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "matrixutils.h" -#include "certificate.h" - -#include <QtCore/QMutex> -#include <QtCore/QObject> - -struct CertificateNode; -class Account; -class CertificateModel; -class QAbstractItemModel; - -class CertificateModelPrivate final : public QObject -{ - Q_OBJECT -public: - CertificateModelPrivate(CertificateModel* parent); - virtual ~CertificateModelPrivate(); - - //Helper - CertificateNode* defaultCategory(); - CertificateNode* createCategory(const QString& name, const QString& col2, const QString& tooltip); - CertificateNode* getCategory(const Account* a); - CertificateNode* addToTree(Certificate* cert, CertificateNode* category = nullptr); - CertificateNode* addToTree(Certificate* cert, Account* a); - void removeFromTree(CertificateNode* node); - void removeFromTree(Certificate* c, CertificateNode* category); - QModelIndex createIndex(int r ,int c , void* p); - QAbstractItemModel* getModelCommon(CertificateNode* node); - bool allowCertificate(Certificate* c, Account* a); - bool banCertificate(Certificate* c, Account* a); - void loadChecks(CertificateNode* checks, Certificate* cert); - void regenChecks(Certificate* cert); - bool isPartOf(CertificateNode* sibling, CertificateNode* list); - - //Attributes - QVector<CertificateNode*> m_lTopLevelNodes ; - QHash<QString,Certificate*> m_hCertificates ; - CertificateNode* m_pDefaultCategory ; - QMutex m_CertLoader ; - QMutex m_CertInsertion ; - int m_GroupCounter ; - QHash<const Account*,CertificateNode*> m_hAccToCat ; - QHash<const QString&,CertificateNode*> m_hStrToCat ; - QHash<const Certificate*,CertificateNode*> m_hNodes ; - static const Matrix1D<Certificate::Status, const char*> m_StatusMap; - mutable QHash<const Account*,QAbstractItemModel*> m_hAccAllow; - mutable QHash<const Account*,QAbstractItemModel*> m_hAccBan ; - mutable QHash<const Account*,CertificateNode*> m_hAccAllowCat; - mutable QHash<const Account*,CertificateNode*> m_hAccBanCat ; - - //Getters - QAbstractItemModel* model (const Certificate* cert) const; - QAbstractItemModel* checksModel (const Certificate* cert) const; - QAbstractItemModel* createKnownList (const Account* a ) const; - QAbstractItemModel* createBannedList (const Account* a ) const; - QAbstractItemModel* createAllowedList (const Account* a ) const; - -private: - CertificateModel* q_ptr; - -private Q_SLOTS: - void slotCertificateStateChanged(const QString& accountId, const QString& certId, const QString& state); -}; diff --git a/src/private/collectionmodel_p.h b/src/private/collectionmodel_p.h deleted file mode 100644 index 02c64f3e7de77df95b5eb35df134d309d77baf44..0000000000000000000000000000000000000000 --- a/src/private/collectionmodel_p.h +++ /dev/null @@ -1,78 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QObject> -#include <QtCore/QVector> -#include <QtCore/QHash> -#include <QtCore/QMutex> -class QAbstractItemModel; - -//Ring -class CollectionInterface; -class CollectionModel; -class CollectionExtensionInterface; -class CollectionConfigurationInterface; -class CollectionCreationInterface; - -class CollectionModelPrivate final : public QObject -{ - Q_OBJECT -public: - explicit CollectionModelPrivate(CollectionModel* parent); - virtual ~CollectionModelPrivate(); - - /* - * This is not very efficient, it doesn't really have to be given the low - * volume. If it ever have to scale, a better mapToSource using persistent - * index have to be implemented. - */ - struct ProxyItem { - ProxyItem() : parent(nullptr),col(0),row(0),collection(nullptr),manageableCount(0){} - virtual ~ProxyItem(); - int row; - int col; - CollectionInterface* collection; - ProxyItem* parent; - QVector<ProxyItem*> m_Children; - QString m_AltName; - int manageableCount; - }; - - QHash<CollectionInterface*,ProxyItem*> m_hBackendsNodes; - QVector<ProxyItem*> m_lTopLevelBackends; - QVector<CollectionExtensionInterface*> m_lExtensions; - QHash<QString,ProxyItem*> m_hCategories; - QAbstractItemModel* m_pManageableProxy; - QList<CollectionConfigurationInterface*> m_lConfigurator; - QList<CollectionCreationInterface*> m_lCreator; - QMutex m_NewCollectionMutex; - QHash<CollectionInterface*,bool> m_hPendingChanges; - - //Helper - void registerNew(CollectionInterface* col); - -private: - CollectionModel* q_ptr; - -private Q_SLOTS: - void slotUpdate(); - void slotExtensionDataChanged(const QModelIndex& idx); -}; - diff --git a/src/private/contactmethod_p.h b/src/private/contactmethod_p.h deleted file mode 100644 index 0d58ca24e862448cfc29ccda9a45c2a2fcb18cfa..0000000000000000000000000000000000000000 --- a/src/private/contactmethod_p.h +++ /dev/null @@ -1,70 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Internal -#include "usage_statistics.h" - -class ContactMethodPrivate { -public: - ContactMethodPrivate(const URI& number, NumberCategory* cat, ContactMethod::Type st, - ContactMethod* q); - NumberCategory* m_pCategory ; - bool m_Present ; - QString m_PresentMessage ; - bool m_Tracked ; - Person* m_pPerson ; - Account* m_pAccount ; - QList<Call*> m_lCalls ; - int m_PopularityIndex ; - QString m_MostCommonName ; - QHash<QString,QPair<int,time_t>> m_hNames; - bool m_hasType ; - int m_Index ; - bool m_IsBookmark ; - QString m_Uid ; - QString m_PrimaryName_cache; - URI m_Uri ; - QByteArray m_Sha1 ; - ContactMethod::Type m_Type ; - QList<URI> m_lOtherURIs ; - Certificate* m_pCertificate; - QString m_RegisteredName ; - UsageStatistics m_UsageStats ; - bool m_Confirmed ; - - //Parents - QList<ContactMethod*> m_lParents; - - //Emit proxies - void callAdded(Call* call); - void changed ( ); - void presentChanged(bool); - void presenceMessageChanged(const QString&); - void trackedChanged(bool); - void primaryNameChanged(const QString& name); - void rebased(ContactMethod* other); - void registeredNameSet(const QString& registeredName); - - //Helpers - void setCertificate (Certificate*); - void setRegisteredName(const QString& registeredName); - - private: - ContactMethod* q_ptr; -}; diff --git a/src/private/imconversationmanagerprivate.h b/src/private/imconversationmanagerprivate.h deleted file mode 100644 index b9e83dde18f82ebfc084f378d7db5dbd6089e41d..0000000000000000000000000000000000000000 --- a/src/private/imconversationmanagerprivate.h +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> -#include <QtCore/QHash> - -class Account; -class Call; -class ContactMethod; - -namespace media { - class Text; -} - -class IMConversationManagerPrivate final : public QObject -{ - Q_OBJECT -public: - friend class Call; - IMConversationManagerPrivate(QObject* parent); - - static IMConversationManagerPrivate& instance(); - -private Q_SLOTS: - void newMessage (const QString& callId , const QString& from, const QMap<QString,QString>& payloads); - void newAccountMessage(const QString& accountId, const QString& from, const QMap<QString,QString>& payloads); - void accountMessageStatusChanged(const QString& accountId, uint64_t id, const QString& to, int status); -}; diff --git a/src/private/macromodel_p.h b/src/private/macromodel_p.h deleted file mode 100644 index 0874952eb4d92201869cc43a6a6f3420df769d7a..0000000000000000000000000000000000000000 --- a/src/private/macromodel_p.h +++ /dev/null @@ -1,89 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <macromodel.h> - -class MacroModelPrivate final : public QObject -{ - Q_OBJECT -public: - enum IndexType { - CategoryIndex = 1, - MacroIndex = 2 - }; - - struct IndexPointer { - IndexPointer(IndexType _type, void* _data) : type(_type),data(_data) {} - IndexType type; - void* data; - }; - - struct MacroCategory { - MacroCategory():m_pPointer(nullptr){} - ~MacroCategory() { delete m_pPointer; } - QString m_Name; - QList<Macro*> m_lContent; - IndexPointer* m_pPointer; - }; - - MacroModelPrivate(MacroModel*); - - //Attributes - QHash<QString,Macro*> m_hMacros ; - QList<MacroCategory*> m_lCategories ; - Macro* m_pCurrentMacro ; - Macro* m_pCurrentMacroMemento ; - QList<MacroModel::MacroListener*> m_lListeners; - - //Helper - MacroCategory* createCategory(const QString& name); - void updateTreeModel(Macro* newMacro); - -private: - MacroModel* q_ptr; - -public Q_SLOTS: - void changed(Macro* macro); -}; - -class MacroPrivate : public QObject -{ - Q_OBJECT -public: - MacroPrivate(); - - //Attributes - int m_Position ; - QString m_Name ; - QString m_Description; - QString m_Sequence ; - QString m_Escaped ; - QString m_Id ; - int m_Delay ; - QString m_Category ; - QVariant m_Action ; - MacroModel* m_pModel ; - - MacroModelPrivate::MacroCategory* m_pCat ; - MacroModelPrivate::IndexPointer* m_pPointer; - -public Q_SLOTS: - void nextStep(); -}; - diff --git a/src/private/matrixutils.h b/src/private/matrixutils.h deleted file mode 100644 index 0c7ecc0641dcc52f73350e2bd87fb71c77368a25..0000000000000000000000000000000000000000 --- a/src/private/matrixutils.h +++ /dev/null @@ -1,199 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//libSTDC++ -#include <initializer_list> -#include <type_traits> - -//Ring -#include <typedefs.h> - -template<class T, class E> -struct TypedStateMachine -{ - // no ctor/dtor and one public member variable for easy initialization - T _data[size_t(E::COUNT__)]; - - T& operator[](E v) { - if (size_t(v) >= size_t(E::COUNT__)) { - Q_ASSERT(false); - qDebug() << "State Machine Out of Bound" << size_t(v); - throw v; - } - return _data[size_t(v)]; - } - - const T& operator[](E v) const { - if (size_t(v) >= size_t(E::COUNT__)) { - Q_ASSERT(false); - qDebug() << "State Machine Out of Bound" << size_t(v); - throw v; - } - return _data[size_t(v)]; - } - - T *begin() { - return _data; - } - - T *end() { - return _data + size_t(E::COUNT__); - } -}; - -template<typename Enum> -class EnumClassReordering { -public: - EnumClassReordering(std::initializer_list<Enum> s); -// private: - Enum m_lData[enum_class_size<Enum>()]; -}; - - -/** - * This generic class represents a multidimensional enum class array. - * It safely converts them to integers. Each enum class needs a "COUNT__" item - * at the end." - * - * This struct enforces: - * * That the rows are indexed using enum_classes - * * That the size of the matrix matches the enum_class size - * * That the operators are within the matrix boundary - */ -template<class Row, typename Value, typename A = Value> -struct Matrix1D -{ - - struct Pairs { - Row key; - Value value; - }; - - struct Order { - const EnumClassReordering<Row> order; - std::initializer_list<Value> vs ; - }; - - Matrix1D(std::initializer_list< std::initializer_list<Value> > s); - Matrix1D(std::initializer_list< Pairs > s); - Matrix1D(std::initializer_list<Order> s); - explicit Matrix1D(); - Matrix1D(const Matrix1D<Row,Value,A>& copy); - ~Matrix1D(); - - // Row is a built-in type ("int" by default) - Value operator[](Row v); - void operator=(Matrix1D<Row,Value,A>& other); - void operator=(std::initializer_list< Pairs > s); - - const Value operator[](Row v) const; - - /** - * An Iterator for enum classes - */ - class Matrix1DEnumClassIter - { - public: - Matrix1DEnumClassIter (Matrix1D<Row, Value, A>* p_vec, int pos) - : pos_( pos ), p_vec_( p_vec ) {} - - bool operator!= (const Matrix1DEnumClassIter& other) const; - bool operator== (const Matrix1DEnumClassIter& other) const; - void operator= (Value& other ) ; - void operator= (Value& other ) const; - //Row operator* () const; - //const Matrix1DEnumClassIter& operator++ (); - - private: - int pos_; - Matrix1D<Row, Value, A> *p_vec_; - }; - - //Iterators - Matrix1DEnumClassIter begin(); - Matrix1DEnumClassIter end(); - - // Only use for single reverse mappable arrays, will ASSERT otherwise - Row fromValue(const Value& value) const; - - static void setReverseMapping(Matrix1D<Row,const char *> names); - - //Setter - void setAt(Row,Value); - - //Getter - bool isSet(Row); - -private: - Value* m_lData[enum_class_size<Row>()]; - static QMap<A, Row> m_hReverseMapping; -}; - -/** - * Create a matrix type with 2 enum class dimensions M[I,J] = V - * ^ ^ ^ - * | | | - * Rows <--- | | - * Columns <----- | - * Value <---------- - */ -template<class Row, class Column, typename Value> -using Matrix2D = Matrix1D<Row, Matrix1D<Column, Value>>; - - -/** - * A matrix with no value - * - * This is useful to use enum class in C++11 foreach loops - * - * @usage - * for (const MyEnum& value : EnumIterator<MyEnum>()) { - * std::cout << "Name: " << MyEnumNames[value] << std::endl; - * } - */ -template<class EnumClass> -struct EnumIterator -{ - /** - * An Iterator for enum classes - */ - class EnumClassIter - { - public: - EnumClassIter (const EnumIterator<EnumClass>* p_vec, int pos) - : pos_( pos ), p_vec_( p_vec ) {} - - bool operator!= (const EnumClassIter& other) const; - EnumClass operator* () const; - const EnumClassIter& operator++ (); - - private: - int pos_; - const EnumIterator<EnumClass> *p_vec_; - }; - - EnumIterator(); - - //Iterators - EnumClassIter begin(); - EnumClassIter end(); -}; - -#include "matrixutils.hpp" - diff --git a/src/private/matrixutils.hpp b/src/private/matrixutils.hpp deleted file mode 100644 index 412f5c1aa9aa88f557db19881de57d0b7bf34891..0000000000000000000000000000000000000000 --- a/src/private/matrixutils.hpp +++ /dev/null @@ -1,277 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2016 by Savoir-faire Linux * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -template<class EnumClass > -EnumIterator<EnumClass>::EnumIterator() { - static_assert(std::is_enum<EnumClass>(),"The first template parameter has to be an enum class\n"); -} - -template<class EnumClass > -EnumClass EnumIterator<EnumClass>::EnumClassIter::operator* () const -{ - Q_ASSERT(pos_ < enum_class_size<EnumClass>()); - return static_cast<EnumClass>(pos_); -} - -template<class EnumClass > -const typename EnumIterator<EnumClass>::EnumClassIter& EnumIterator<EnumClass>::EnumClassIter::operator++ () -{ - ++pos_; - return *this; -} - -template<class EnumClass > -bool EnumIterator<EnumClass>::EnumClassIter::operator!= (const EnumClassIter& other) const -{ - return pos_ != other.pos_; -} - -template< class EnumClass > -typename EnumIterator<EnumClass>::EnumClassIter EnumIterator<EnumClass>::begin() -{ - return EnumIterator<EnumClass>::EnumClassIter( this, 0 ); -} - -template<class EnumClass > -typename EnumIterator<EnumClass>::EnumClassIter EnumIterator<EnumClass>::end() -{ - return EnumIterator<EnumClass>::EnumClassIter( this, enum_class_size<EnumClass>() ); -} - -template<class Row, typename Value, typename Accessor> -Matrix1D<Row,Value,Accessor>::Matrix1D() : m_lData{nullptr} -{ -} - -template<class Row, typename Value, typename Accessor> -Matrix1D<Row,Value,Accessor>::Matrix1D(const Matrix1D<Row,Value,Accessor>& copy) : m_lData{nullptr} -{ - for (int i = 0; i < enum_class_size<Row>(); i++) { - m_lData[i] = new Value(*copy.m_lData[i]); - } -} - -template<class Row, typename Value, typename Accessor> -Matrix1D<Row,Value,Accessor>::~Matrix1D() -{ - for (auto v : m_lData) - delete v; -} - -//DEPRECATED -template<class Row, typename Value, typename Accessor> -Matrix1D<Row,Value,Accessor>::Matrix1D(std::initializer_list< std::initializer_list<Value>> s) -: m_lData{nullptr} { - static_assert(std::is_enum<Row>(),"Row has to be an enum class"); - static_assert(static_cast<int>(Row::COUNT__) > 0,"Row need a COUNT__ element"); - - //This version assume the rows are valid, use the one below where possible - for (auto& rows : s) { - int row = 0; - for (auto& value : rows) { - m_lData[row] = new Value(value); - row++; - } - } - - // FIXME C++14, use static_assert and make the ctor constexpr - Q_ASSERT(std::begin(s)->size() == enum_class_size<Row>());//,"Matrix row have to match the enum class size"); -} - -template<typename Enum> -EnumClassReordering<Enum>::EnumClassReordering(std::initializer_list<Enum> s) -{ - static_assert(std::is_enum<Enum>(),"Row has to be an enum class"); - Q_ASSERT(s.size() == enum_class_size<Enum>()); - - //FIXME the code below isn't correct, this isn't a problem until the limit - //is reached. This is private API, so it can wait - static const int longSize = sizeof(unsigned long long)*8; - Q_ASSERT(enum_class_size<Enum>() < longSize -1); - - unsigned long long usedElements[enum_class_size<Enum>()] = {}; - - int i=0; - for (auto& p : s) { - const int val = static_cast<int>(p); - Q_ASSERT(!(usedElements[val/longSize] & (0x1 << (val%longSize)))); // isNotPresent - usedElements[val/longSize] |= (0x1 << (val%longSize)); - m_lData[i++] = p; - } -} - -template<class Row, typename Value, typename Accessor> -Matrix1D<Row,Value,Accessor>::Matrix1D(std::initializer_list< Matrix1D<Row,Value,Accessor>::Order > s) -: m_lData{} { - static_assert(std::is_enum<Row>(),"Row has to be an enum class"); - static_assert(static_cast<int>(Row::COUNT__) > 0,"Row need a COUNT__ element"); - Q_ASSERT(s.size() == 1); - - for (const Matrix1D<Row,Value,Accessor>::Order& p : s) { - // FIXME C++14, use static_assert and make the ctor constexpr - Q_ASSERT(p.vs.size() == enum_class_size<Row>()); - - int reOredered[enum_class_size<Row>()],i(0); - for (const Row r : p.order.m_lData) - reOredered[i++] = static_cast<int>(r); - - i = 0; - for (auto& r : p.vs) - m_lData[reOredered[i++]] = new Value(r); - - } - -} - -/** - * Safest version of the constructor, checks that all values are present, that - * they are present only once and support re-ordering - */ -template<class Row, typename Value, typename Accessor> -Matrix1D<Row,Value,Accessor>::Matrix1D(std::initializer_list< Matrix1D<Row,Value,Accessor>::Pairs> s) -: m_lData{} { - static_assert(std::is_enum<Row>(),"Row has to be an enum class"); - static_assert(static_cast<int>(Row::COUNT__) > 0,"Row need a COUNT__ element"); - - static const int longSize = sizeof(unsigned long long)*8; - - //FIXME the code below isn't correct, this isn't a problem until the limit - //is reached. This is private API, so it can wait - Q_ASSERT(enum_class_size<Row>() < longSize -1); - - unsigned long long usedElements[enum_class_size<Row>()] = {}; - - int counter = 0; - for (auto& pair : s) { - //Avoid a value being here twice - const int val = static_cast<int>(pair.key); - Q_ASSERT(!(usedElements[val/longSize] & (0x1 << (val%longSize)))); // isNotPresent - - usedElements[val/longSize] |= (0x1 << (val%longSize)); - - - m_lData[val] = new Value(pair.value); - counter++; - } - - // FIXME C++14, use static_assert and make the ctor constexpr - Q_ASSERT(counter == enum_class_size<Row>());//,"Matrix row have to match the enum class size"); -} - -template<class Row, typename Value, typename Accessor> -Value Matrix1D<Row,Value,Accessor>::operator[](Row v) { - //ASSERT(size_t(v) >= size_t(Row::COUNT__),"State Machine Out of Bounds\n"); - if (size_t(v) >= enum_class_size<Row>() || static_cast<int>(v) < 0) { - qWarning() << "State Machine Out of Bounds" << size_t(v); - Q_ASSERT(false); - throw v; - } - return *m_lData[static_cast<int>(v)]; -} - -template<class Row, typename Value, typename Accessor> -const Value Matrix1D<Row,Value,Accessor>::operator[](Row v) const { - Q_ASSERT(size_t(v) <= enum_class_size<Row>()+1 && size_t(v)>=0); //COUNT__ is also valid - if (size_t(v) >= enum_class_size<Row>()) { - qWarning() << "State Machine Out of Bounds" << size_t(v); - Q_ASSERT(false); - throw v; - } - Q_ASSERT(m_lData[static_cast<int>(v)]); - - return *(m_lData[static_cast<int>(v)]); -} - -template<class Row, typename Value, typename Accessor> -void Matrix1D<Row,Value,Accessor>::operator=(Matrix1D<Row,Value,Accessor>& other) -{ - for (int i = 0; i < enum_class_size<Row>(); i++) { - m_lData[i] = new Value(*other.m_lData[i]); - } -} - -template<class Row, typename Value, typename Accessor> -void Matrix1D<Row,Value,Accessor>::operator=(std::initializer_list< Pairs > s) -{ - Matrix1D<Row,Value,Accessor> m(s); - (*this) = m; -} - -template <class E, class T, class A> QMap<A,E> Matrix1D<E,T,A>::m_hReverseMapping; - -template<class Row, typename Value, typename Accessor> -void Matrix1D<Row,Value,Accessor>::setReverseMapping(Matrix1D<Row,const char*> names) -{ - for ( const Row row : EnumIterator<Row>() ) - m_hReverseMapping[names[row]] = row; -} - -template<class Row, typename Value, typename Accessor> -Row Matrix1D<Row,Value,Accessor>::fromValue(const Value& value) const { - if (!m_hReverseMapping.empty()) { - for (int i = 0; i < enum_class_size<Row>();i++) { - const_cast<Matrix1D*>(this)->m_hReverseMapping[(*const_cast<Matrix1D*>(this))[(Row)i]] - = static_cast<Row>(i); - } - Q_ASSERT(m_hReverseMapping.empty() == enum_class_size<Row>()); - } - if (m_hReverseMapping.count(value) == 0) { - throw value; - } - return m_hReverseMapping[value]; -} - -template<class Row, typename Value, typename Accessor> -bool Matrix1D<Row,Value,Accessor>::Matrix1DEnumClassIter::operator!= (const Matrix1DEnumClassIter& other) const -{ - return pos_ != other.pos_; -} - -template<class Row, typename Value, typename Accessor> -bool Matrix1D<Row,Value,Accessor>::Matrix1DEnumClassIter::operator== (const Matrix1DEnumClassIter& other) const -{ - return pos_ == other.pos_; -} - -template<class Row, typename Value, typename Accessor> -void Matrix1D<Row,Value,Accessor>::Matrix1DEnumClassIter::operator= (Value& other) const -{ - p_vec_->m_lData[pos_] = &other; -} - -template<class Row, typename Value, typename Accessor> -void Matrix1D<Row,Value,Accessor>::Matrix1DEnumClassIter::operator= (Value& other) -{ - p_vec_->m_lData[pos_] = &other; -} - -///@return if the value was changed (return false for identical values) -template<class Row, typename Value, typename Accessor> -void Matrix1D<Row,Value,Accessor>::setAt(Row row,Value value) -{ - if (m_lData[(int)row]) - delete m_lData[(int)row]; - - m_lData[(int)row] = new Value(value); -} - -template<class Row, typename Value, typename Accessor> -bool Matrix1D<Row,Value,Accessor>::isSet(Row row) -{ - return m_lData[static_cast<int>(row)] != nullptr; -} diff --git a/src/private/media_p.h b/src/private/media_p.h deleted file mode 100644 index 2ba077401b032ef6fbaec8d4d8e729acf441a759..0000000000000000000000000000000000000000 --- a/src/private/media_p.h +++ /dev/null @@ -1,57 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <media/media.h> -#include "private/matrixutils.h" - - -namespace media { -class MediaPrivate; - -typedef bool (MediaPrivate::*MediaTransitionFct)(); - -class MediaPrivate -{ - friend class media::Media; -public: - MediaPrivate(Media* parent); - - static const Matrix2D<media::Media::State, media::Media::Action, bool> m_mValidTransitions; - static const Matrix2D<media::Media::State, media::Media::Action, MediaTransitionFct> m_mCallbacks; - - //Actions - bool mute (); - bool unmute (); - bool terminate(); - bool nothing (); - - //Server changes callbacks - void muteConfirmed(); - void unmuteConfirmed(); - -private: - //Attributes - media::Media::State m_State; - Call* m_pCall; - media::Media::Direction m_Direction; - - Media* q_ptr; -}; - -} diff --git a/src/private/numbercategorymodel_p.h b/src/private/numbercategorymodel_p.h deleted file mode 100644 index 508d66073461113f34f5f3de5de10da2b2aebb01..0000000000000000000000000000000000000000 --- a/src/private/numbercategorymodel_p.h +++ /dev/null @@ -1,43 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -class NumberCategoryModelPrivate -{ -public: - struct InternalTypeRepresentation { - NumberCategory* category; - int index ; - bool enabled ; - int counter ; - }; - - //Attributes - QVector<InternalTypeRepresentation*> m_lCategories ; - QHash<int,InternalTypeRepresentation*> m_hByIdx ; - QHash<QString,InternalTypeRepresentation*> m_hByName ; - QHash<const NumberCategory*,InternalTypeRepresentation*> m_hToInternal ; - - //Mutator - void registerNumber ( ContactMethod* number ); //FIXME this should be private - void unregisterNumber( ContactMethod* number ); - int getSize ( const NumberCategory* cat ) const; - - virtual ~NumberCategoryModelPrivate(); -}; - diff --git a/src/private/person_p.h b/src/private/person_p.h deleted file mode 100644 index 8c776640d5569e17b62394d96efd03bf1ee026c7..0000000000000000000000000000000000000000 --- a/src/private/person_p.h +++ /dev/null @@ -1,88 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2009-2019 Savoir-faire Linux Inc. * - * Author : Jérémy Quentin <jeremy.quentin@savoirfairelinux.com> * - * Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -//std -#include <time.h> - -//Ring -#include "person.h" -class ContactMethod; - -class PersonPrivate final : public QObject -{ - Q_OBJECT - friend class ContactMethod; -public: - explicit PersonPrivate(Person* contact); - ~PersonPrivate(); - QString m_FirstName ; - QString m_SecondName ; - QString m_NickName ; - QVariant m_vPhoto ; - QString m_FormattedName ; - QString m_PreferredEmail ; - QString m_Organization ; - QByteArray m_Uid ; - QString m_Group ; - QString m_Department ; - bool m_DisplayPhoto ; - Person::ContactMethods m_Numbers ; - bool m_Active ; - bool m_isPlaceHolder ; - QList<Person::Address> m_lAddresses ; - QHash<QString, QString> m_lCustomAttributes ; - ::time_t m_LastUsed ; - bool m_LastUsedInit ; - QList<ContactMethod*> m_HiddenContactMethods; - - /* - * NOTE If new attributes are added, please update the explicit Person copy - * constructor as Qt force QObject copy via serialization (to force developers - * to use references, copy-on-write based containers and smart pointers - * instead), which is overkill for this scenario and would detach all the - * containers causing useless increase in memory usage. - */ - - //Cache - QString m_CachedFilterString; - - QString filterString(); - - //Helper code to help handle multiple parents - QList<Person*> m_lParents; - Person* q_ptr; - - //As a single D-Pointer can have multiple parent (when merged), all emit need - //to use a proxy to make sure everybody is notified - void presenceChanged ( ContactMethod* ); - void statusChanged ( bool ); - void changed ( ); - void phoneNumbersChanged ( ); - void phoneNumbersAboutToChange( ); - - //Helper - void registerContactMethod(ContactMethod* m); - -public Q_SLOTS: - void slotLastUsedTimeChanged(::time_t t); - void slotCallAdded (Call *call); -}; diff --git a/src/private/phonedirectorymodel_p.h b/src/private/phonedirectorymodel_p.h deleted file mode 100644 index cb346236feba399a169a32dd1894d39862676581..0000000000000000000000000000000000000000 --- a/src/private/phonedirectorymodel_p.h +++ /dev/null @@ -1,111 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -//Ring -class PhoneDirectoryModel; -#include "contactmethod.h" -#include "namedirectory.h" - -//Internal data structures -///@struct NumberWrapper Wrap phone numbers to prevent collisions -struct NumberWrapper { - QVector<ContactMethod*> numbers; -}; - -class MostPopularNumberModel final : public QAbstractListModel -{ - Q_OBJECT -public: - explicit MostPopularNumberModel(); - - //Model functions - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - - void addRow(); - void reload(); -}; - -class PhoneDirectoryModelPrivate final : public QObject -{ - Q_OBJECT -public: - explicit PhoneDirectoryModelPrivate(PhoneDirectoryModel* parent); - - - //Model columns - enum class Columns { - URI = 0, - TYPE = 1, - CONTACT = 2, - ACCOUNT = 3, - STATE = 4, - CALL_COUNT = 5, - WEEK_COUNT = 6, - TRIM_COUNT = 7, - HAVE_CALLED = 8, - LAST_USED = 9, - NAME_COUNT = 10, - TOTAL_SECONDS = 11, - POPULARITY_INDEX = 12, - BOOKMARED = 13, - TRACKED = 14, - HAS_CERTIFICATE = 15, - PRESENT = 16, - PRESENCE_MESSAGE = 17, - UID = 18, - REGISTERED_NAME = 19, - }; - - - //Helpers - void indexNumber(ContactMethod* number, const QStringList& names ); - void setAccount (ContactMethod* number, Account* account ); - ContactMethod* fillDetails(NumberWrapper* wrap, const URI& strippedUri, Account* account, Person* contact, const QString& type); - - //Attributes - QVector<ContactMethod*> m_lNumbers ; - QHash<QString,NumberWrapper*> m_hDirectory ; - QVector<ContactMethod*> m_lPopularityIndex ; - QMap<QString,NumberWrapper*> m_lSortedNames ; - QMap<QString,NumberWrapper*> m_hSortedNumbers ; - QHash<QString,NumberWrapper*> m_hNumbersByNames ; - bool m_CallWithAccount ; - MostPopularNumberModel* m_pPopularModel ; - - Q_DECLARE_PUBLIC(PhoneDirectoryModel) - -private: - PhoneDirectoryModel* q_ptr; - -private Q_SLOTS: - void slotCallAdded(Call* call); - void slotChanged(); - void slotLastUsedChanged(time_t t); - void slotContactChanged(Person* newContact, Person* oldContact); - void slotRegisteredNameFound(const Account* account, NameDirectory::LookupStatus status, const QString& address, const QString& name); - void slotContactMethodMerged(ContactMethod* other); - - //From DBus - void slotNewBuddySubscription(const QString& uri, const QString& accountId, bool status, const QString& message); -}; diff --git a/src/private/securityevaluationmodel_p.h b/src/private/securityevaluationmodel_p.h deleted file mode 100644 index c10975e023460d8343308f7994a771437961563a..0000000000000000000000000000000000000000 --- a/src/private/securityevaluationmodel_p.h +++ /dev/null @@ -1,67 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -class SecurityFlaw; -class Account; -class Certificate; -class AccountChecksModel; - -#include <certificate.h> -#include "private/matrixutils.h" -#include <securityevaluationmodel.h> - -class SecurityEvaluationModelPrivate final : public QObject -{ - Q_OBJECT -public: - SecurityEvaluationModelPrivate(Account* account, SecurityEvaluationModel* parent); - - //Attributes - QList<SecurityFlaw*> m_lCurrentFlaws ; - SecurityEvaluationModel::SecurityLevel m_CurrentSecurityLevel; - Account* m_pAccount ; - QHash< int, QHash< int, SecurityFlaw* > > m_hFlaws; - bool m_isScheduled; - int m_SeverityCount[enum_class_size<SecurityEvaluationModel::Severity>()]; - - AccountChecksModel* m_pAccChecks; - - //Helper - static SecurityEvaluationModel::SecurityLevel maxSecurityLevel(QAbstractItemModel* m, int* counter = nullptr); - static QAbstractItemModel* getCertificateSeverityProxy(Certificate* c); - static SecurityEvaluationModel::SecurityLevel certificateSecurityLevel(const Certificate* c, bool forceIgnorePrivateKey = false); - - ///Messages to show to the end user - static const QString messages[enum_class_size<SecurityEvaluationModel::AccountSecurityChecks>()]; - - //Static mapping - static const TypedStateMachine< SecurityEvaluationModel::SecurityLevel , SecurityEvaluationModel::AccountSecurityChecks > maximumSecurityLevel; - static const TypedStateMachine< SecurityEvaluationModel::Severity , SecurityEvaluationModel::AccountSecurityChecks > flawSeverity ; - - static const TypedStateMachine< SecurityEvaluationModel::SecurityLevel , Certificate::Checks > maximumCertificateSecurityLevel; - static const TypedStateMachine< SecurityEvaluationModel::Severity , Certificate::Checks > certificateFlawSeverity ; - - SecurityEvaluationModel* q_ptr; - -public Q_SLOTS: - void update(); - void updateReal(); - -}; - diff --git a/src/private/securityflaw_p.h b/src/private/securityflaw_p.h deleted file mode 100644 index fbd899359b3555b986d3f2e75e9300574fcfa9d6..0000000000000000000000000000000000000000 --- a/src/private/securityflaw_p.h +++ /dev/null @@ -1,39 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#include "securityevaluationmodel.h" -class SecurityFlaw; - -class SecurityFlawPrivate final : public QObject -{ - Q_OBJECT -public: - SecurityFlawPrivate(SecurityFlaw* parent, SecurityEvaluationModel::AccountSecurityChecks f,Certificate::Type type); - - //Attributes - SecurityEvaluationModel::AccountSecurityChecks m_flaw; - SecurityEvaluationModel::Severity m_severity; - Certificate::Type m_certType; - int m_Row; - - SecurityFlaw* q_ptr; -}; - diff --git a/src/private/sortproxies.cpp b/src/private/sortproxies.cpp deleted file mode 100644 index 7159faa76a1d1202b7ec514718f9fc3010633513..0000000000000000000000000000000000000000 --- a/src/private/sortproxies.cpp +++ /dev/null @@ -1,198 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "sortproxies.h" - -//LibSTDC++ -#include <functional> - -//Qt -#include <QtCore/QAbstractListModel> -#include <QtCore/QItemSelectionModel> -#include <QtCore/QSortFilterProxyModel> - -//Ring -#include "matrixutils.h" -#include <globalinstances.h> -#include <interfaces/pixmapmanipulatori.h> - -namespace CategoryModelCommon { - inline Qt::ItemFlags flags(const QModelIndex& idx) { - return idx.isValid()?Qt::ItemIsEnabled|Qt::ItemIsSelectable : Qt::NoItemFlags; - } - - bool setData( const QModelIndex& index, const QVariant &value, int role); - bool setData( const QModelIndex& index, const QVariant &value, int role) { - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; - } -} - -class RemoveDisabledProxy : public QSortFilterProxyModel -{ - Q_OBJECT -public: - explicit RemoveDisabledProxy(QObject* parent) : QSortFilterProxyModel(parent) { - setDynamicSortFilter(true); - } -protected: - virtual bool filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const override; -}; - -class ContactSortingCategoryModel : public QAbstractListModel -{ - Q_OBJECT -public: - ContactSortingCategoryModel(QObject* parent = nullptr); - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual ~ContactSortingCategoryModel(); -}; - -class HistorySortingCategoryModel : public QAbstractListModel -{ - Q_OBJECT -public: - HistorySortingCategoryModel(QObject* parent = nullptr); - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual ~HistorySortingCategoryModel(); -}; - -bool RemoveDisabledProxy::filterAcceptsRow ( int source_row, const QModelIndex & source_parent ) const -{ - const Qt::ItemFlags flags = sourceModel()->index(source_row,0,source_parent).flags(); - if (!(flags & Qt::ItemIsEnabled)) - return false; - else if (!source_parent.isValid() || source_parent.parent().isValid()) - return true; - - return QSortFilterProxyModel::filterAcceptsRow(source_row, source_parent); -} - -ContactSortingCategoryModel::ContactSortingCategoryModel(QObject* parent) : QAbstractListModel(parent) -{ - -} - -ContactSortingCategoryModel::~ContactSortingCategoryModel() -{ - -} - -void sortContact(QSortFilterProxyModel* p, int roleIdx); -void sortContact(QSortFilterProxyModel* p, int roleIdx) -{ -} - -QVariant ContactSortingCategoryModel::data( const QModelIndex& index, int role ) const -{ - return QVariant(); -} - -int ContactSortingCategoryModel::rowCount( const QModelIndex& parent) const -{ - return 0; -} - -Qt::ItemFlags ContactSortingCategoryModel::flags( const QModelIndex& index ) const -{ - return CategoryModelCommon::flags(index); -} - -bool ContactSortingCategoryModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - return CategoryModelCommon::setData(index,value,role); -} - -void sortHistory(QSortFilterProxyModel* p, int role); -void sortHistory(QSortFilterProxyModel* p, int role) -{ - -} - -HistorySortingCategoryModel::HistorySortingCategoryModel(QObject* parent) : QAbstractListModel(parent) -{ - -} - -HistorySortingCategoryModel::~HistorySortingCategoryModel() -{ - -} - -QVariant HistorySortingCategoryModel::data( const QModelIndex& index, int role) const -{ - return QVariant(); -} - -int HistorySortingCategoryModel::rowCount( const QModelIndex& parent) const -{ - return 0; -} - -Qt::ItemFlags HistorySortingCategoryModel::flags( const QModelIndex& index ) const -{ - return CategoryModelCommon::flags(index); -} - -bool HistorySortingCategoryModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - return CategoryModelCommon::setData(index,value,role); -} - -template<typename T> -SortingCategory::ModelTuple* createModels(QAbstractItemModel* src, int filterRole, int sortRole, std::function<void(QSortFilterProxyModel*,const QModelIndex&)> callback) -{ - SortingCategory::ModelTuple* ret = new SortingCategory::ModelTuple; - - ret->categories = new T(src); - - QSortFilterProxyModel* proxy = new RemoveDisabledProxy(src); - proxy->setSortRole ( sortRole ); - proxy->setSortLocaleAware ( true ); - proxy->setFilterRole ( filterRole ); - proxy->setSortCaseSensitivity ( Qt::CaseInsensitive ); - proxy->setFilterCaseSensitivity ( Qt::CaseInsensitive ); - ret->model = proxy; - ret->model->setSourceModel(src); - - ret->selectionModel = new QItemSelectionModel(ret->model); - QObject::connect(ret->selectionModel, &QItemSelectionModel::currentChanged,[proxy,callback](const QModelIndex& idx) { - callback(proxy,idx); - }); - - return ret; -} - -SortingCategory::ModelTuple* SortingCategory::getContactProxy() -{ - return nullptr; -} - -SortingCategory::ModelTuple* SortingCategory::getHistoryProxy() -{ - return nullptr; -} - -#include <sortproxies.moc> diff --git a/src/private/sortproxies.h b/src/private/sortproxies.h deleted file mode 100644 index 5da153d17aa058bf127a560a31a02c1213b2aef6..0000000000000000000000000000000000000000 --- a/src/private/sortproxies.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -class QAbstractListModel; -class QItemSelectionModel; -class QSortFilterProxyModel; - -/* - * This file is dedicated to store the various sorting possibilities - * - * As they can share some helper code in common and would only add noise - * to their "real" source model, They are placed here. - */ - -namespace SortingCategory { - struct ModelTuple { - QAbstractListModel* categories ; - QSortFilterProxyModel* model ; - QItemSelectionModel* selectionModel; - }; - - ModelTuple* getContactProxy(); - ModelTuple* getHistoryProxy(); -} diff --git a/src/private/textrecording_p.h b/src/private/textrecording_p.h deleted file mode 100644 index ae1a7023a7f8fdecc4058a0c2cab38c3ed1aba7b..0000000000000000000000000000000000000000 --- a/src/private/textrecording_p.h +++ /dev/null @@ -1,256 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -//Qt -#include <QtCore/QAbstractListModel> -#include <QtCore/QRegExp> -#include <QtCore/QRegularExpression> - -//Daemon -#include <account_const.h> - -//Ring -#include "media/media.h" -#include "media/textrecording.h" - -class SerializableEntityManager; -struct TextMessageNode; -class InstantMessagingModel; -class ContactMethod; - -namespace media { - class TextRecording; -} - -//BEGIN Those classes are serializable to JSon -/** - * Those classes map 1:1 to the json stored on the disk. References are then - * extracted, the conversation reconstructed and placed into a TextMessageNode - * vector. - */ -namespace Serializable { - -class Payload { -public: - QString payload; - QString mimeType; - - void read (const QJsonObject &json); - void write(QJsonObject &json) const; -}; - -class Message { -public: - enum class Type { - CHAT , /*!< Normal message between the peer */ - STATUS, /*!< "Room status" message, such as new participants or participants that left */ - }; - - ///The time associated with this message - time_t timestamp ; - ///A group of alternate payloads (mimetype as key) - QList<Payload*> payloads ; - ///The author display name - QString authorSha1; - ///The direction - media::Media::Direction direction ; - ///The message Type - Type type ; - ///If the message have been read - bool isRead ; - ///The contact method (incoming messages only) - ContactMethod* contactMethod ; - //The token of the message - uint64_t id ; - //Delivery Status - media::TextRecording::Status deliveryStatus; - - static const QRegularExpression m_linkRegex; - - //Cache the most common payload to avoid lookup - QString m_PlainText; - QString m_HTML; - QString m_FormattedHtml; - QList<QUrl> m_LinkList; - bool m_HasText; - - void read (const QJsonObject &json); - void write(QJsonObject &json) const; - const QString& getFormattedHtml(); -}; - -class Peer { -public: - QString accountId; - ///The peer URI - QString uri; - ///The peer contact UID - QString personUID; - ///The ContactMethod hash - QString sha1; - - ContactMethod* m_pContactMethod; - - void read (const QJsonObject &json); - void write(QJsonObject &json) const; -}; - - -class Group { -public: - ///The group ID (necessary to untangle the graph - int id; - ///All messages from this chunk - QList<Message*> messages; - ///If the conversion add new participants, a new file will be created - QString nextGroupSha1; - ///This is the group identifier in the file described by `nextGroupSha1` - int nextGroupId; - ///The account used for this conversation - - void read (const QJsonObject &json, const QHash<QString,ContactMethod*> sha1s); - void write(QJsonObject &json) const; -}; - -class Peers { - friend class ::SerializableEntityManager; -public: - - ///The sha1(s) of each participants. If there is onlt one, it should match the filename - QList<QString> sha1s; - ///Every message groups associated with this ContactMethod (or ContactMethodGroup) - QList<Group*> groups; - ///Information about every (non self) peer involved in this group - QList<Peer*> peers; - - ///This attribute store if the file has changed - bool hasChanged; - - ///Keep a cache of the peers sha1 - QHash<QString,ContactMethod*> m_hSha1; - - void read (const QJsonObject &json); - void write(QJsonObject &json) const; - -private: - Peers() : hasChanged(false) {} -}; - -} -//END Those classes are serializable to JSon - -namespace media { - -/** - * The Media::Recording private class. This is where the reconstructed - * conversation is stored. This class is also used as backend for the - * IM Model. The messages themselves are added by the Media::Text. - */ -class TextRecordingPrivate { -public: - explicit TextRecordingPrivate(TextRecording* r); - - //Attributes - InstantMessagingModel* m_pImModel ; - QVector<::TextMessageNode*> m_lNodes ; - Serializable::Group* m_pCurrentGroup ; - QList<Serializable::Peers*> m_lAssociatedPeers ; - QHash<QString,bool> m_hMimeTypes ; - int m_UnreadCount ; - QStringList m_lMimeTypes ; - QAbstractItemModel* m_pTextMessagesModel {nullptr}; - QAbstractItemModel* m_pUnreadTextMessagesModel {nullptr}; - QHash<uint64_t, TextMessageNode*> m_hPendingMessages; - - //Helper - void insertNewMessage(const QMap<QString,QString>& message, ContactMethod* cm, media::Media::Direction direction, uint64_t id = 0); - QHash<QByteArray,QByteArray> toJsons() const; - void accountMessageStatusChanged(const uint64_t id, DRing::Account::MessageStates status); - bool updateMessageStatus(Serializable::Message* m, TextRecording::Status status); - - void clear(); - -private: - TextRecording* q_ptr; -}; - -} //Media:: - - -/** - * This class ensure that only one Serializable::Peer structure exist for each - * peer [group]. - */ -class SerializableEntityManager -{ -public: - static Serializable::Peers* peer(const ContactMethod* cm); - static Serializable::Peers* peers(QList<const ContactMethod*> cms); - static Serializable::Peers* fromSha1(const QByteArray& sha1); - static Serializable::Peers* fromJson(const QJsonObject& obj, const ContactMethod* cm = nullptr); -private: - static QHash<QByteArray,Serializable::Peers*> m_hPeers; -}; - -/** - * This is the structure used internally to create the text conversation - * frontend. It will be stored as a vector by the IM Model but also implement - * a chained list for convenience - */ -struct TextMessageNode -{ - TextMessageNode() : m_pNext(nullptr),m_pContactMethod(nullptr) - {} - - Serializable::Message* m_pMessage ; - ContactMethod* m_pContactMethod; - TextMessageNode* m_pNext ; - int m_row ; -}; - -///Model for the Instant Messaging (IM) features -class InstantMessagingModel final : public QAbstractListModel -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - -public: - - //Constructor - explicit InstantMessagingModel(media::TextRecording*); - virtual ~InstantMessagingModel(); - - //Abstract model function - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - void clear(); - - //Attributes - media::TextRecording* m_pRecording; - - //Helper - void addRowBegin(); - void addRowEnd(); -}; diff --git a/src/private/threadworker.cpp b/src/private/threadworker.cpp deleted file mode 100644 index 7914b9fe8c13e7e4d09011573bd7a6b562fdf2db..0000000000000000000000000000000000000000 --- a/src/private/threadworker.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "threadworker.h" - -//Qt -#include <QtCore/QThread> -#include <QtCore/QDebug> -#include <QtCore/QCoreApplication> - -//LibStdC++ -#include <functional> - -ThreadWorker::ThreadWorker(std::function<void()> f) : QObject(nullptr) -{ - QThread* t = new QThread(); - - connect(t, &QThread::finished, t, &QObject::deleteLater); - - moveToThread(t); - - QObject::connect(t, &QThread::started, [this,f]() { - - f(); - - thread()->exit(); - - moveToThread(QCoreApplication::instance()->thread()); - - delete this; - }); - - t->start(); -} \ No newline at end of file diff --git a/src/private/threadworker.h b/src/private/threadworker.h deleted file mode 100644 index b87753b018aa8b2a3e6519999cbc81875d6ca8eb..0000000000000000000000000000000000000000 --- a/src/private/threadworker.h +++ /dev/null @@ -1,40 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#ifdef __clang__ //Forward declaring std::function doesn't work on Clang - #include <functional> -#else - namespace std { - template<typename T> - class function; - } -#endif - -/** - * Small utility to avoid the Qt4/C++03 boiler plate code for workers. There - * doesn't seem to be a Qt5/C++11 way yet. - */ -class ThreadWorker : public QObject -{ - Q_OBJECT -public: - ThreadWorker(std::function<void()> f); -}; diff --git a/src/private/useractions.h b/src/private/useractions.h deleted file mode 100644 index 202ac4659960491c087c903340b7167368ca948c..0000000000000000000000000000000000000000 --- a/src/private/useractions.h +++ /dev/null @@ -1,473 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -// Qt -#include <QtCore/QProcess> -#include <QtCore/QMimeData> -#include <QtCore/QStringBuilder> - -// LRC -#include <categorizedbookmarkmodel.h> -#include <categorizedhistorymodel.h> -#include <personmodel.h> -#include <interfaces/actionextenderi.h> -#include <interfaces/itemmodelstateserializeri.h> -#include <mime.h> - -#include "media/media.h" -#include "media/audio.h" -#include "media/video.h" - -/** - * This code used to be in the KDE client. It doesn't really fit well in well - * in what libringclient is supposed to do, but as it has to be replicated for - * each clients, then UserActionModel will provide an abstract way to call those - * functions. - */ -namespace UserActions { - -bool addNew ( ); -bool accept ( Call* call ); -bool hangup ( Call* call ); -bool refuse ( Call* call ); -bool hold ( Call* call ); -bool unhold ( Call* call ); -bool transfer ( Call* call ); -bool recordAudio ( Call* call ); -bool recordVideo ( Call* call ); -bool recordText ( Call* call ); -bool muteAudio ( Call* call, bool state ); -bool muteVideo ( Call* call, bool state ); -bool sendEmail ( const Person* p ); -bool callAgain ( ContactMethod* cm ); -bool bookmark ( ContactMethod* cm ); -bool deleteContact ( Person* p ); -bool removeFromHistory( Call* c ); -bool editPerson ( Person* p ); -bool addToPerson ( ContactMethod* cm ); -bool addToPerson ( Person* p ); - -bool addPerson(ContactMethod* cm, CollectionInterface* col = nullptr); - -bool addNew() -{ - Call* call = CallModel::instance().dialingCall(); - CallModel::instance().selectionModel()->setCurrentIndex(CallModel::instance().getIndex(call), QItemSelectionModel::ClearAndSelect); - return true; -} - -bool accept(Call* call) -{ - bool ret = true; - - //Add a new call if none is there - if (!call) { - return addNew(); - } - - const Call::State state = call->state(); - //TODO port to lifeCycle code - if (state == Call::State::RINGING || state == Call::State::CURRENT || state == Call::State::HOLD - || state == Call::State::BUSY || state == Call::State::FAILURE || state == Call::State::ERROR) { - qDebug() << "Calling when item currently ringing, current, hold or busy. Opening an item."; - Call* c2 = CallModel::instance().dialingCall(); - CallModel::instance().selectionModel()->setCurrentIndex(CallModel::instance().getIndex(c2), QItemSelectionModel::ClearAndSelect); - } - else { - try { - call->performAction(Call::Action::ACCEPT); - } - catch(const char * msg) { - ret = false; - } - } - return ret; -} //accept - -///Call -bool hangup(Call* call) -{ - bool ret = true; - - if (call) { - try { - call->performAction(Call::Action::REFUSE); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} //hangup - -///Refuse call -bool refuse(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Hanging up when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::REFUSE); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Put call on hold -bool hold(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Holding when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::HOLD); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Remove call from hold -bool unhold(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Un-Holding when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::HOLD); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Transfer a call -bool transfer(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Transferring when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::TRANSFER); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Record a call -bool recordAudio(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Recording when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::RECORD_AUDIO); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Record a call -bool recordVideo(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Recording when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::RECORD_VIDEO); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Record a call -bool recordText(Call* call) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Recording when no item selected. Should not happen."; - } - else { - try { - call->performAction(Call::Action::RECORD_TEXT); - } - catch(const char * msg) { - return false; - } - } - - return ret; -} - -///Mute call audio -bool muteAudio(Call* call, bool state) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Muting audio when no item selected. Should not happen."; - return false; - } - auto audioOut = call->firstMedia<media::Audio>(media::Media::Direction::OUT); - if (!audioOut) { - qDebug() << "Error : No audio media for this call"; - return false; - } - if (state) { - if (!audioOut->mute()) - qDebug() << "Error : Could not mute audio of selected call"; - } else { - if (!audioOut->unmute()) - qDebug() << "Error : Could not un-mute audio of selected call"; - } - - return ret; -} - -///Mute call video -bool muteVideo(Call* call, bool state) -{ - bool ret = true; - - if(!call) { - qDebug() << "Error : Muting video when no item selected. Should not happen."; - return false; - } - auto videoOut = call->firstMedia<media::Video>(media::Media::Direction::OUT); - if (!videoOut) { - qDebug() << "Error : No video media for this call"; - return false; - } - if (state) { - if (!videoOut->mute()) - qDebug() << "Error : Could not mute video of selected call"; - } else { - if (!videoOut->unmute()) - qDebug() << "Error : Could not un-mute video of selected call"; - } - - return ret; -} - -bool sendEmail(const Person* p) -{ - if (!p || p->preferredEmail().isEmpty()) - return false; - - qDebug() << "Sending email"; - QProcess *myProcess = new QProcess(QCoreApplication::instance()); - QStringList arguments; -#ifdef Q_OS_WIN32 - myProcess->start("start", { "mailto:"+p->preferredEmail() }); -#elif defined Q_OS_DARWIN - myProcess->start("open", { "mailto:"+p->preferredEmail() }); -#else - myProcess->start("xdg-email", { "mailto:"+p->preferredEmail() }); -#endif - return true; -} - -bool callAgain(ContactMethod* cm) -{ - if (!cm) - return false; - - Call* call = CallModel::instance().dialingCall(cm); - - if (call) { - call->performAction(Call::Action::ACCEPT); - return true; - } - - return false; -} - -bool bookmark(ContactMethod* cm) -{ - if (!cm) - return false; - - CategorizedBookmarkModel::instance().addBookmark(cm); - - return true; -} - -bool deleteContact(Person* p) -{ - if (!p) - return false; - - if (GlobalInstances::actionExtender().warnDeletePerson(p)) - return p->remove(); - - return false; -} - -bool removeFromHistory(Call* c) -{ - if (c && c->collection()->supportedFeatures() & CollectionInterface::SupportedFeatures::REMOVE) { - - if (GlobalInstances::actionExtender().warnDeleteCall(c)) { - CategorizedHistoryModel::instance().deleteItem(c); //TODO add add and remove to the manager - return true; - } - } - - return false; -} - -/** - * If the client want GUI edition, this can be implemented as part of the - * collection edition features themselves. - */ -bool editPerson( Person* p ) -{ - if (!p) - return false; - - return p->edit(); -} - -bool addPerson(ContactMethod* cm, CollectionInterface* col) -{ - // If the placeholder has not yet been replaced, it might point to a - // deleted contact, as the user initiated this action, lets comply - if (cm->contact() && !cm->contact()->isPlaceHolder()) - return false; - - // Try to get the best collection for this - if (!col) - col = GlobalInstances::itemModelStateSerializer().preferredCollection( - &PersonModel::instance(), - CollectionInterface::SupportedFeatures::ADD - ); - - // Take a random collection that match - if (!col) { - const QVector<CollectionInterface*> cols = PersonModel::instance() - .collections(CollectionInterface::SupportedFeatures::ADD); - - if (cols.isEmpty()) - return false; - - //TODO support collection selection - col = cols.first(); - } - - Person* p = new Person(); - - p->setFormattedName(cm->primaryName()); - p->setContactMethods({cm}); - - cm->setPerson(p); - - col->add(p); - - Q_ASSERT_X(p->collection() == col, - "addPerson", - "The collection doesn't match. This is an internal Ring bug, please " - "report it" - ); - - if (!p->save()) - return false; - - return editPerson(p); -} - -bool addToPerson(ContactMethod* cm) -{ - if (!cm) - return false; - - Person* p = GlobalInstances::actionExtender().selectPerson(); - - if (!p || !(p->collection()->supportedFeatures() & CollectionInterface::SupportedFeatures::EDIT)) - return false; - - auto numbers = p->phoneNumbers(); - numbers << cm; - p->setContactMethods(numbers); - - return p->save(); -} - -bool addToPerson(Person* p) -{ - if (!p || !(p->collection()->supportedFeatures() & CollectionInterface::SupportedFeatures::EDIT)) - return false; - - ContactMethod* cm = GlobalInstances::actionExtender().selectContactMethod( - Interfaces::ActionExtenderI::SelectContactMethodHint::RECENT | - Interfaces::ActionExtenderI::SelectContactMethodHint::WITHOUT_PERSON - ); - - if (!cm) - return false; - - auto numbers = p->phoneNumbers(); - numbers << cm; - p->setContactMethods(numbers); - - return p->save(); -} - -} //namespace UserActions diff --git a/src/private/vcardutils.cpp b/src/private/vcardutils.cpp deleted file mode 100644 index 742657742f278b99ac66eb86359964eca2d4da2e..0000000000000000000000000000000000000000 --- a/src/private/vcardutils.cpp +++ /dev/null @@ -1,502 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "vcardutils.h" - -//Qt -#include <QtCore/QBuffer> -#include <QtCore/QDir> -#include <QtCore/QFile> -#include <QtCore/QUrl> -#include <QtCore/QMimeData> -#include <QtCore/QMutex> - -//Ring -#include "phonedirectorymodel.h" -#include "contactmethod.h" -#include "accountmodel.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "personmodel.h" - -/* https://www.ietf.org/rfc/rfc2045.txt - * https://www.ietf.org/rfc/rfc2047.txt - * https://www.ietf.org/rfc/rfc2426.txt - */ - -//BEGIN:VCARD -//VERSION:3.0 -//N:Gump;Forrest -//FN:Forrest Gump -//ORG:Bubba Gump Shrimp Co. -//TITLE:Shrimp Man -//PHOTO;VALUE=URL;TYPE=GIF:http://www.example.com/dir_photos/my_photo.gif -//TEL;TYPE=WORK,VOICE:(111) 555-1212 -//TEL;TYPE=HOME,VOICE:(404) 555-1212 -//ADR;TYPE=WORK:;;100 Waters Edge;Baytown;LA;30314;United States of America -//LABEL;TYPE=WORK:100 Waters Edge\nBaytown, LA 30314\nUnited States of America -//ADR;TYPE=HOME:;;42 Plantation St.;Baytown;LA;30314;United States of America -//LABEL;TYPE=HOME:42 Plantation St.\nBaytown, LA 30314\nUnited States of America -//EMAIL;TYPE=PREF,INTERNET:forrestgump@example.com -//REV:20080424T195243Z -//END:VCARD - -struct VCardMapper; - -typedef void (VCardMapper:: *mapToProperty)(Person*, const QString&, const QByteArray&); - -struct VCardMapper final { - - QHash<QByteArray, mapToProperty> m_hHash; - - // Calling getNumber before the Contact is finalized will create duplicates - struct GetNumberFuture { - QByteArray uri; - Person* c; - QString category; - }; - - QHash<Person*, QList<GetNumberFuture> > m_hDelayedCMInserts; - static QMutex* m_pMutex; - - VCardMapper() { - m_hHash[VCardUtils::Property::UID] = &VCardMapper::setUid; - m_hHash[VCardUtils::Property::NAME] = &VCardMapper::setNames; - m_hHash[VCardUtils::Property::FORMATTED_NAME] = &VCardMapper::setFormattedName; - m_hHash[VCardUtils::Property::EMAIL] = &VCardMapper::setEmail; - m_hHash[VCardUtils::Property::ORGANIZATION] = &VCardMapper::setOrganization; - m_hHash[VCardUtils::Property::TELEPHONE] = &VCardMapper::addContactMethod; - m_hHash[VCardUtils::Property::ADDRESS] = &VCardMapper::addAddress; - m_hHash[VCardUtils::Property::PHOTO] = &VCardMapper::setPhoto; - } - - void apply() { - // Finalize the transaction, set the ContactsMethods - // it is done at the end to make sure UID has been set and all CMs - // are there at once not to mess PhoneDirectoryModel detection - - QMutexLocker locker(m_pMutex); - - for (QHash<Person*, QList<GetNumberFuture>>::iterator i = m_hDelayedCMInserts.begin(); i != m_hDelayedCMInserts.end(); ++i) { - Person::ContactMethods m = i.key()->phoneNumbers(); - - foreach(const GetNumberFuture& v, i.value()) { - ContactMethod* cm = PhoneDirectoryModel::instance().getNumber(v.uri,v.c,nullptr,v.category); - - m << cm; - } - i.key()->setContactMethods(m); - } - - m_hDelayedCMInserts.clear(); - } - - void setFormattedName(Person* c, const QString&, const QByteArray& fn) { - c->setFormattedName(QString::fromUtf8(fn)); - } - - void setNames(Person* c, const QString&, const QByteArray& fn) { - QList<QByteArray> splitted = fn.split(';'); - if (splitted.length() > 0) - c->setFamilyName(splitted.at(0).trimmed()); - if (splitted.length() > 1) - c->setFirstName(splitted.at(1).trimmed()); - } - - void setUid(Person* c, const QString&, const QByteArray& fn) { - c->setUid(fn); - } - - void setEmail(Person* c, const QString&, const QByteArray& fn) { - c->setPreferredEmail(fn); - } - - void setOrganization(Person* c, const QString&, const QByteArray& fn) { - c->setOrganization(QString::fromUtf8(fn)); - } - - void setPhoto(Person* c, const QString& key, const QByteArray& fn) { - QByteArray type = "PNG"; - - QRegExp rx(QStringLiteral("TYPE=([A-Za-z]*)")); - - while ((rx.indexIn(key, 0)) != -1) { - type = rx.cap(1).toLatin1(); - break; - } - - QVariant photo = GlobalInstances::pixmapManipulator().personPhoto(fn,type); - c->setPhoto(photo); - } - - void addContactMethod(Person* c, const QString& key, const QByteArray& fn) { - QByteArray type; - - QRegExp rx(QStringLiteral("TYPE=([A-Za-z,]*)")); - - //VCard spec: it is RECOMMENDED that property and parameter names - // be upper-case on output. - rx.setCaseSensitivity(Qt::CaseInsensitive); - - while ((rx.indexIn(key, 0)) != -1) { - type = rx.cap(1).toLatin1(); - break; - } - - // TODO: Currently we only support one type (the first on the line) TYPE=WORK,VOICE: <number> - const QStringList categories = QString(type).split(','); - - m_hDelayedCMInserts[c] << GetNumberFuture { - fn, - c, - categories.size()?categories[0]:QString() - }; - } - - void addAddress(Person* c, const QString& key, const QByteArray& fn) { - auto addr = Person::Address(); - QList<QByteArray> fields = fn.split(VCardUtils::Delimiter::SEPARATOR_TOKEN[0]); - QStringList keyFields = key.split(VCardUtils::Delimiter::SEPARATOR_TOKEN); - - if(keyFields.size() < 2 || fields.size() < 7) { - qDebug() << "Malformatted Address"; - return; - } - - addr.setType (keyFields[1] ); - addr.setAddressLine (QString::fromUtf8(fields[2]) ); - addr.setCity (QString::fromUtf8(fields[3]) ); - addr.setState (QString::fromUtf8(fields[4]) ); - addr.setZipCode (QString::fromUtf8(fields[5]) ); - addr.setCountry (QString::fromUtf8(fields[6]) ); - - c->addAddress(addr); - } - - bool metacall(Person* c, const QByteArray& key, const QByteArray& value) { - const QStringList settings = QString(key).split(';'); - if (settings.length() < 1) - return false; - - if (!m_hHash[settings[0].toLatin1()]) { - if(key.contains(VCardUtils::Property::PHOTO)) { - //key must contain additional attributes, we don't need them right now (ENCODING, TYPE...) - setPhoto(c, key, value); - return true; - } - - if(key.contains(VCardUtils::Property::ADDRESS)) { - addAddress(c, key, value); - return true; - } - - if(key.contains(VCardUtils::Property::TELEPHONE)) { - addContactMethod(c, key, value); - return true; - } - - return false; - } - (this->*(m_hHash[settings[0].toLatin1()]))(c,key,value); - return true; - } -}; - -QMutex* VCardMapper::m_pMutex = new QMutex(); -static VCardMapper* vc_mapper = new VCardMapper; - -VCardUtils::VCardUtils() -{ - -} - -void VCardUtils::startVCard(const QString& version) -{ - m_vCard << Delimiter::BEGIN_TOKEN; - addProperty(Property::VERSION, version); -} - -void VCardUtils::addProperty(const char* prop, const QString& value) -{ - if (value.isEmpty() || value == QString(';')) - return; - m_vCard << (QString::fromUtf8(prop) + ':' + value); -} - -void VCardUtils::addProperty(const QString& prop, const QString& value) -{ - if (value.isEmpty() || value == QString(';')) - return; - m_vCard << (prop + ':' + value); -} - -void VCardUtils::addEmail(const QString& type, const QString& email) -{ - addProperty(QString("%1%2%3%4").arg(Property::EMAIL).arg(Delimiter::SEPARATOR_TOKEN).arg("TYPE=").arg(type), email); -} - -void VCardUtils::addAddress(const Person::Address& addr) -{ - QString prop = QString("%1%2%3").arg(Property::ADDRESS) - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(addr.type()); - - //First two fields are left empty for now, they are for Postal box and Extended Address - QString value = QString("%1%2%3%4%5%6%7%8%9%10%11") - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(addr.addressLine()) - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(addr.city()) - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(addr.state()) - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(addr.zipCode()) - .arg(Delimiter::SEPARATOR_TOKEN) - .arg(addr.country()); - - addProperty(prop, value); -} - -void VCardUtils::addContactMethod(const QString& type, const QString& num) -{ - QString prop = QString(Property::TELEPHONE) + QString(Delimiter::SEPARATOR_TOKEN) + type; - addProperty(prop, num); -} - -void VCardUtils::addPhoto(const QByteArray img, bool convertToBase64) -{ - auto b64Img = convertToBase64 ? img.toBase64().trimmed() : img.trimmed(); - m_vCard << (QString::fromUtf8(Property::PHOTO) + - QString::fromUtf8(Delimiter::SEPARATOR_TOKEN) + - "ENCODING=BASE64" + - QString::fromUtf8(Delimiter::SEPARATOR_TOKEN) + - "TYPE=PNG:" + b64Img); -} - -const QByteArray VCardUtils::endVCard() -{ - m_vCard << Delimiter::END_TOKEN; - const QString result = m_vCard.join(QString::fromUtf8(Delimiter::END_LINE_TOKEN)); - return result.toUtf8(); -} - -QList< Person* > VCardUtils::loadDir (const QUrl& path, bool& ok, QHash<const Person*,QString>& paths) -{ - QList< Person* > ret; - - QDir dir(path.toString()); - if (!dir.exists()) - ok = false; - else { - ok = true; - for (const QString& file : dir.entryList({"*.vcf"},QDir::Files)) { - Person* p = new Person(); - mapToPerson(p,QUrl(dir.absoluteFilePath(file))); - ret << p; - paths[p] = dir.absoluteFilePath(file); - } - } - - return ret; -} - -bool VCardUtils::mapToPerson(Person* p, const QByteArray& all, QList<Account*>* accounts) -{ - QByteArray previousKey,previousValue; - const QList<QByteArray> lines = all.split('\n'); - - foreach (const QByteArray& property, lines) { - //Ignore empty lines - if (property.size()) { - //Some properties are over multiple lines - if (property[0] == ' ' && previousKey.size()) { - previousValue += property.right(property.size()-1); - } - else { - if (previousKey.size()) - vc_mapper->metacall(p,previousKey,previousValue.trimmed()); - - //Do not use split, URIs can have : in them - const int dblptPos = property.indexOf(':'); - const QByteArray k(property.left(dblptPos)),v(property.right(property.size()-dblptPos-1)); - - //Link with accounts - if(k == VCardUtils::Property::X_RINGACCOUNT) { - if (accounts) { - Account* a = AccountModel::instance().getById(v.trimmed(),true); - if(!a) { - qDebug() << "Could not find account: " << v.trimmed(); - continue; - } - - (*accounts) << a; - } - } - - previousKey = k; - previousValue = v; - } - - } - - } - - vc_mapper->apply(); - - return true; -} - -bool VCardUtils::mapToPerson(Person* p, const QUrl& path, QList<Account*>* accounts) -{ - - QFile file(path.toString()); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - qDebug() << "Error opening vcard: " << path; - return false; - } - - const QByteArray all = file.readAll(); - - return mapToPerson(p,all,accounts); -} - -Person* VCardUtils::mapToPerson(const QHash<QByteArray, QByteArray>& vCard, QList<Account*>* accounts) -{ - auto existingPerson = PersonModel::instance().getPersonByUid(vCard[Property::UID]); - auto personMapped = existingPerson == nullptr ? new Person() : existingPerson; - - QHashIterator<QByteArray, QByteArray> it(vCard); - while (it.hasNext()) { - it.next(); - if (it.key() == VCardUtils::Property::X_RINGACCOUNT) { - if (accounts) { - auto acc = AccountModel::instance().getById(it.value().trimmed(),true); - if (!acc) { - qDebug() << "Could not find account: " << it.value().trimmed(); - continue; - } - (*accounts) << acc; - } - } - vc_mapper->metacall(personMapped, it.key(), it.value().trimmed()); - } - - vc_mapper->apply(); - return personMapped; -} - -/** - * There are many instances when we can receive a payload which contains a vCard. The vCard is - * received from a ContactMethod so we want to check if this CM already has a Person we want to - * update from the new vCard, or else create a new Person. We also can't trust the contents of the - * vCard, so we ignore any idenitication info and only basically use the name and the photo. - * - * @param contactMethod, the contactMethod from which we received the profile - * @param payload, the profile we received - */ -Person* VCardUtils::mapToPersonFromReceivedProfile(ContactMethod *contactMethod, const QByteArray& payload) -{ - /* TODO: here we only check if this ContatMethod has a Person already; however it possible that - * another CM with the same RingID (but associated with a different Account) has a profile - * already; in this case we probably want to update that Person as well (since its coming) - * from the same RingID, or maybe even use that Person and add this CM to its list of - * numbers - */ - auto person = contactMethod->contact(); - if (!person) { - person = new Person(); - person->setContactMethods({contactMethod}); - contactMethod->setPerson(person); - } - auto vCard = toHashMap(payload); - - QHashIterator<QByteArray, QByteArray> it(vCard); - while (it.hasNext()) { - it.next(); - - // Do not trust a ringid from an incoming vcard, it could have been falsified. - if (it.key() == VCardUtils::Property::TELEPHONE) continue; - // Do not trust UID from incoming vcard, we can't be sure that its unique, we will generate our own - if (it.key() == VCardUtils::Property::UID) continue; - // This shouldn't be there anyways, but ignore it if it is - if (it.key() == VCardUtils::Property::X_RINGACCOUNT) continue; - - vc_mapper->metacall(person, it.key(), it.value().trimmed()); - } - - vc_mapper->apply(); - - return person; -} - -QHash<QByteArray, QByteArray> VCardUtils::toHashMap(const QByteArray& content) -{ - QHash<QByteArray, QByteArray> vCard; - QByteArray previousKey,previousValue; - const QList<QByteArray> lines = content.split('\n'); - - foreach (const QByteArray& property, lines) { - //Ignore empty lines - if (property.size()) { - //Some properties are over multiple lines - if (property[0] == ' ' && previousKey.size()) { - previousValue += property.right(property.size()-1); - } - - //Do not use split, URIs can have : in them - const int dblptPos = property.indexOf(':'); - const QByteArray k(property.left(dblptPos)),v(property.right(property.size()-dblptPos-1)); - vCard[k] = v; - } - } - return vCard; -} - -//TODO get the daemon implementation, port it to Qt -QByteArray VCardUtils::wrapInMime(const QString& mimeType, const QByteArray& payload) -{ - QByteArray a; - a += "MIME-Version: 1.0\n"; - a += "Content-Type: multipart/mixed; boundary=content\n"; - a += "\n"; - a += "--content\n"; - a += "Content-Type: "+mimeType+"\n"; - a += "\n"; - a += payload+"\n"; - a += "--content--\0"; - - return a; -} - -QMap<QString, QString> VCardUtils::parseMimeAttributes(const QString& mimeType) -{ - QMap<QString, QString> ret; - - const auto& list = mimeType.split(';'); - if (list.size() < 2) - return {}; - - const auto& pairs = list[1].split(','); - for(const auto& p: pairs) { - const auto& kv = p.split('='); - ret[kv[0].trimmed()] = kv[1]; - } - - return ret; -} diff --git a/src/private/vcardutils.h b/src/private/vcardutils.h deleted file mode 100644 index 7baec6b1ed8621715de980f785a362c3b1c93281..0000000000000000000000000000000000000000 --- a/src/private/vcardutils.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include "typedefs.h" -#include <QStringList> -#include "person.h" - -class VCardUtils -{ -public: - - struct Delimiter { - constexpr static const char* SEPARATOR_TOKEN = ";"; - constexpr static const char* END_LINE_TOKEN = "\n"; - constexpr static const char* BEGIN_TOKEN = "BEGIN:VCARD"; - constexpr static const char* END_TOKEN = "END:VCARD"; - }; - - struct Property { - constexpr static const char* UID = "UID"; - constexpr static const char* VERSION = "VERSION"; - constexpr static const char* ADDRESS = "ADR"; - constexpr static const char* AGENT = "AGENT"; - constexpr static const char* BIRTHDAY = "BDAY"; - constexpr static const char* CATEGORIES = "CATEGORIES"; - constexpr static const char* CLASS = "CLASS"; - constexpr static const char* DELIVERY_LABEL = "LABEL"; - constexpr static const char* EMAIL = "EMAIL"; - constexpr static const char* FORMATTED_NAME = "FN"; - constexpr static const char* GEOGRAPHIC_POSITION = "GEO"; - constexpr static const char* KEY = "KEY"; - constexpr static const char* LOGO = "LOGO"; - constexpr static const char* MAILER = "MAILER"; - constexpr static const char* NAME = "N"; - constexpr static const char* NICKNAME = "NICKNAME"; - constexpr static const char* NOTE = "NOTE"; - constexpr static const char* ORGANIZATION = "ORG"; - constexpr static const char* PHOTO = "PHOTO"; - constexpr static const char* PRODUCT_IDENTIFIER = "PRODID"; - constexpr static const char* REVISION = "REV"; - constexpr static const char* ROLE = "ROLE"; - constexpr static const char* SORT_STRING = "SORT-STRING"; - constexpr static const char* SOUND = "SOUND"; - constexpr static const char* TELEPHONE = "TEL"; - constexpr static const char* TIME_ZONE = "TZ"; - constexpr static const char* TITLE = "TITLE"; - constexpr static const char* URL = "URL"; - - constexpr static const char* X_RINGACCOUNT = "X-RINGACCOUNTID"; - }; - - VCardUtils(); - - void startVCard(const QString& version); - void addProperty(const char* prop, const QString& value); - void addProperty(const QString& prop, const QString& value); - void addEmail(const QString& type, const QString& num); - void addAddress(const Person::Address& addr); - void addContactMethod(const QString& type, const QString& num); - void addPhoto(const QByteArray img, bool convertToBase64 = true); - const QByteArray endVCard(); - - //Loading - static QList<Person*> loadDir(const QUrl& path, bool& ok, QHash<const Person*, QString>& paths); - - //Mapping - static bool mapToPerson(Person* p, const QUrl& url, QList<Account*>* accounts = nullptr); - static bool mapToPerson(Person* p, const QByteArray& content, QList<Account*>* accounts = nullptr); - static Person* mapToPerson(const QHash<QByteArray, QByteArray>& vCard, QList<Account*>* accounts = nullptr); - static Person* mapToPersonFromReceivedProfile(ContactMethod *contactMethod, const QByteArray& payload); - static QHash<QByteArray, QByteArray> toHashMap(const QByteArray& content); - - //Serialization - static QByteArray wrapInMime(const QString& mimeType, const QByteArray& payload); - static QMap<QString,QString> parseMimeAttributes(const QString& mimeType); - -private: - - //Attributes - QStringList m_vCard; - -}; diff --git a/src/private/videochannel_p.h b/src/private/videochannel_p.h deleted file mode 100644 index 94e17d5ec368fd40a39bd3c3718ca2304808fed2..0000000000000000000000000000000000000000 --- a/src/private/videochannel_p.h +++ /dev/null @@ -1,29 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -class VideoChannelPrivate -{ -public: - VideoChannelPrivate(); - QString m_Name; - QList<Video::Resolution*> m_lValidResolutions; - Video::Resolution* m_pCurrentResolution; - Video::Device* m_pDevice; -}; - diff --git a/src/private/videodevice_p.h b/src/private/videodevice_p.h deleted file mode 100644 index b5dbc533ba33185944ad680abdf1826d0a5e13f7..0000000000000000000000000000000000000000 --- a/src/private/videodevice_p.h +++ /dev/null @@ -1,53 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> -#include <QtCore/QList> - -namespace Video { - class Channel; - class Device; -} - -class VideoDevicePrivate final : public QObject -{ - Q_OBJECT -public: - class PreferenceNames { - public: - constexpr static const char* RATE = "rate" ; - constexpr static const char* NAME = "name" ; - constexpr static const char* CHANNEL = "channel"; - constexpr static const char* SIZE = "size" ; - }; - - explicit VideoDevicePrivate(Video::Device* parent = nullptr); - - //Attributes - QString m_DeviceId ; - Video::Channel* m_pCurrentChannel; - QList<Video::Channel*> m_lChannels ; - bool m_RequireSave ; - - Video::Device* q_ptr; - -public Q_SLOTS: - void saveIdle(); -}; - diff --git a/src/private/videorate_p.h b/src/private/videorate_p.h deleted file mode 100644 index eef0fcd7b015591e705f846fe53d0c299689df8d..0000000000000000000000000000000000000000 --- a/src/private/videorate_p.h +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -namespace Video { - class Resolution; -} - -class RatePrivate -{ -public: - QString m_Name; - const Video::Resolution* m_pResolution; -}; - diff --git a/src/private/videorenderer_p.h b/src/private/videorenderer_p.h index 25c14ed80b80f11c20c17b154139f88f772ffe7b..5f98475e50b9ce3408818bb704707be8b2060736 100644 --- a/src/private/videorenderer_p.h +++ b/src/private/videorenderer_p.h @@ -22,6 +22,8 @@ #include <QtCore/QObject> #include <QtCore/QSize> +#include "api/newvideo.h" + // Std #include <atomic> #include <memory> @@ -31,7 +33,6 @@ class QMutex; namespace Video { class Renderer; -struct Frame; class RendererPrivate final : public QObject { @@ -44,7 +45,7 @@ public: QMutex* m_pMutex ; QString m_Id ; QSize m_pSize ; - std::shared_ptr<Frame> m_pFrame; // frame given by daemon for direct rendering + std::shared_ptr<lrc::api::video::Frame> m_pFrame; // frame given by daemon for direct rendering private: Video::Renderer* q_ptr; }; diff --git a/src/private/videorenderermanager.cpp b/src/private/videorenderermanager.cpp deleted file mode 100644 index f6ed8baf9120fea538c869fad984d76ac3618902..0000000000000000000000000000000000000000 --- a/src/private/videorenderermanager.cpp +++ /dev/null @@ -1,444 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Authors : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com>* - * Alexandre Lision <alexandre.lision@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "videorenderermanager.h" - -//libstdc++ -#include <vector> - -//Qt -#include <QtCore/QMutex> - -//Ring -#include <dbus/videomanager.h> -#include <video/device.h> -#include <call.h> -#include <video/renderer.h> -#include <video/devicemodel.h> -#include <video/channel.h> -#include <video/rate.h> -#include <video/resolution.h> -#include "private/videorate_p.h" -#include "private/call_p.h" - -#ifdef ENABLE_LIBWRAP - #include "directrenderer.h" -#else - #include "shmrenderer.h" -#endif - -constexpr static const char PREVIEW_RENDERER_ID[] = "local"; - -class VideoRendererManagerPrivate final : public QObject -{ - Q_OBJECT - -public: - VideoRendererManagerPrivate(VideoRendererManager* parent); - - //Attributes - bool m_PreviewState; - uint m_BufferSize ; - QHash<QByteArray,Video::Renderer*> m_hRenderers ; - QHash<Video::Renderer*,QByteArray> m_hRendererIds; - QHash<Video::Renderer*, QThread*> m_hThreads ; - bool m_usingAVFrame ; - - //Helper - void removeRenderer(Video::Renderer* r); - -private: - VideoRendererManager* q_ptr; - -public Q_SLOTS: - void startedDecoding(const QString& id, const QString& shmPath, int width, int height); - void stoppedDecoding(const QString& id, const QString& shmPath); - void callIsOver(); - -}; - -VideoRendererManagerPrivate::VideoRendererManagerPrivate(VideoRendererManager* parent) : QObject(parent), q_ptr(parent), -m_BufferSize(0),m_PreviewState(false) -{ - -} - -///Constructor -VideoRendererManager::VideoRendererManager():QObject(QCoreApplication::instance()), d_ptr(new VideoRendererManagerPrivate(this)) -{ - VideoManagerInterface& interface = VideoManager::instance(); - connect( &interface , &VideoManagerInterface::startedDecoding, d_ptr.data(), &VideoRendererManagerPrivate::startedDecoding); - connect( &interface , &VideoManagerInterface::stoppedDecoding, d_ptr.data(), &VideoRendererManagerPrivate::stoppedDecoding); -} - -void -VideoRendererManager::deactivate() -{ - // Used for retrocompability and avoid multiple renderer - VideoManagerInterface& interface = VideoManager::instance(); - disconnect( &interface , &VideoManagerInterface::startedDecoding, d_ptr.data(), &VideoRendererManagerPrivate::startedDecoding); - disconnect( &interface , &VideoManagerInterface::stoppedDecoding, d_ptr.data(), &VideoRendererManagerPrivate::stoppedDecoding); -} -void -VideoRendererManager::useAVFrame(bool useAVFrame) { - d_ptr->m_usingAVFrame = useAVFrame; -} - -VideoRendererManager::~VideoRendererManager() -{ -// delete d_ptr; -} - -///Singleton -VideoRendererManager& VideoRendererManager::instance() -{ - static auto instance = new VideoRendererManager; - return *instance; -} - -int VideoRendererManager::size() const -{ - return d_ptr->m_hRenderers.size(); -} - -///Return the call Renderer or nullptr -Video::Renderer* VideoRendererManager::getRenderer(const Call* call) const -{ - if ((!call) || (!call->hasRemote()) || !d_ptr->m_hRenderers.contains(call->dringId().toLatin1())) - return nullptr; - - return d_ptr->m_hRenderers[call->dringId().toLatin1()]; -} - -// helper for the new model -Video::Renderer* VideoRendererManager::getRenderer(const std::string& callId) const -{ - return (d_ptr->m_hRenderers.contains(callId.c_str())) - ? d_ptr->m_hRenderers[callId.c_str()] - : nullptr; -} - -///Get the video preview Renderer -Video::Renderer* VideoRendererManager::previewRenderer() -{ - if (!d_ptr->m_hRenderers.contains(PREVIEW_RENDERER_ID)) { - - if ((!Video::DeviceModel::instance().activeDevice()) || (!Video::DeviceModel::instance().activeDevice()->activeChannel())) { - qWarning() << "No device found"; - return nullptr; - } - - Video::Resolution* res = Video::DeviceModel::instance().activeDevice()->activeChannel()->activeResolution(); - - if (!res) { - qWarning() << "Misconfigured video device"; - return nullptr; - } - - Video::Renderer* r = nullptr; - -#ifdef ENABLE_LIBWRAP - r = new Video::DirectRenderer(PREVIEW_RENDERER_ID, res->size(), d_ptr->m_usingAVFrame); -#else //ENABLE_LIBWRAP - r = new Video::ShmRenderer(PREVIEW_RENDERER_ID,"",res->size()); -#endif - - QThread* t = new QThread(this); - d_ptr->m_hThreads[r] = t; - - r->moveToThread(t); - - d_ptr->m_hRenderers[PREVIEW_RENDERER_ID] = r; - d_ptr->m_hRendererIds[r] = PREVIEW_RENDERER_ID; - - } - return d_ptr->m_hRenderers[PREVIEW_RENDERER_ID]; -} - -///Stop video preview -void VideoRendererManager::stopPreview() -{ - // If an active call does not have video muted, don't stop the camera - // stopCamera() calls switchInput(""), which disables the camera - bool previewShouldBeStopped = true; - for (auto it = d_ptr->m_hRenderers.begin(); it != d_ptr->m_hRenderers.end(); ++it) { - if (it.key() != PREVIEW_RENDERER_ID) - // If rendering, don't stop preview - previewShouldBeStopped &= !it.value()->isRendering(); - } - if (previewShouldBeStopped) - VideoManager::instance().stopCamera(); - - d_ptr->m_PreviewState = false; -} - -///Start video preview -void VideoRendererManager::startPreview() -{ - if (d_ptr->m_PreviewState) - return; - - VideoManager::instance().startCamera(); - - d_ptr->m_PreviewState = true; -} - -///Is the video model fetching preview from a camera -bool VideoRendererManager::isPreviewing() const -{ - return d_ptr->m_PreviewState; -} - -///@todo Set the video buffer size -void VideoRendererManager::setBufferSize(uint size) -{ - d_ptr->m_BufferSize = size; -} - -///A video is not being rendered -void VideoRendererManagerPrivate::startedDecoding(const QString& id, const QString& shmPath, int width, int height) -{ - Q_UNUSED(shmPath) //When directly linked, there is no SHM - const QSize res = QSize(width,height); - const QByteArray rid = id.toLatin1(); - - qWarning() << "startedDecoding for sink id: " << id; - - Video::Renderer* r = nullptr; - - if (!m_hRenderers.contains(rid)) { - -#ifdef ENABLE_LIBWRAP - - r = new Video::DirectRenderer(rid, res, m_usingAVFrame); - - qWarning() << "Calling registerFrameListener"; - m_hRenderers[rid] = r; - m_hRendererIds[r]=rid; - if (m_usingAVFrame) { - VideoManager::instance().registerAVSinkTarget(id, static_cast<Video::DirectRenderer*>(r)->avTarget()); - } else { - VideoManager::instance().registerSinkTarget(id, static_cast<Video::DirectRenderer*>(r)->target()); - } - -#else //ENABLE_LIBWRAP - - r = new Video::ShmRenderer(rid,shmPath,res); - m_hRenderers[rid] = r; - m_hRendererIds[r]=rid; - -#endif - - QThread* t = new QThread(this); - m_hThreads[r] = t; - - r->moveToThread(t); - - if (!t->isRunning()) - t->start(); - - } - else { - r = m_hRenderers.value(rid); - - QThread* t = m_hThreads.value(r); - - if (t && !t->isRunning()) - t->start(); - - r->setSize(res); - -#ifdef ENABLE_LIBWRAP - if (m_usingAVFrame) { - VideoManager::instance().registerAVSinkTarget(id, static_cast<Video::DirectRenderer*>(r)->avTarget()); - } else { - VideoManager::instance().registerSinkTarget(id, static_cast<Video::DirectRenderer*>(r)->target()); - } -#else //ENABLE_LIBWRAP - - static_cast<Video::ShmRenderer*>(r)->setShmPath(shmPath); - -#endif - - } - - r->startRendering(); - - Video::Device* dev = Video::DeviceModel::instance().getDevice(id); - - if (dev) - emit dev->renderingStarted(r); - - if (id != PREVIEW_RENDERER_ID) { - qDebug() << "Starting video for call" << id; - - emit q_ptr->remotePreviewStarted(id.toStdString(), r); - - } - else { - m_PreviewState = true; - emit q_ptr->previewStateChanged(true); - emit q_ptr->previewStarted(r); - } -} - -/// Deletes the renderer and related resources -#ifndef Q_OS_WIN -void VideoRendererManagerPrivate::removeRenderer(Video::Renderer* r) -{ - const auto id = m_hRendererIds.value(r); - auto t = m_hThreads.value(r); - - m_hRendererIds.remove(r); - m_hRenderers.remove(id); - m_hThreads.remove(r); - - if (t) { - t->deleteLater(); - } - - r->deleteLater(); -} - -/** - * A video stopped being rendered - * - * @warning This method can be called multiple time for the same renderer - */ -void VideoRendererManagerPrivate::stoppedDecoding(const QString& id, const QString& shmPath) -{ - Q_UNUSED(shmPath) - - if (!m_hRenderers.contains(id.toLatin1()) || !m_hRenderers.contains(id.toLatin1())) { - qWarning() << "Cannot stop decoding, renderer" << id << "not found"; - return; // nothing to do - } - - auto r = m_hRenderers.value(id.toLatin1()); - - r->stopRendering(); - - qDebug() << "Video stopped for call" << id << "Renderer found:" << m_hRenderers.contains(id.toLatin1()); - - Video::Device* dev = Video::DeviceModel::instance().getDevice(id); - - if (dev) - emit dev->renderingStopped(r); - - if (id == PREVIEW_RENDERER_ID) { - m_PreviewState = false; - emit q_ptr->previewStateChanged(false); - emit q_ptr->previewStopped(r); - } - - QThread* t = m_hThreads.value(r); - - if (t) { - t->quit(); - t->wait(); - } - - // decoding stopped; remove the renderer, if/when call is over - removeRenderer(r); -} - -void VideoRendererManagerPrivate::callIsOver() -{ - if (auto call = qobject_cast<Call *>(sender())) { - if (auto r = m_hRenderers.value(call->dringId().toLatin1())) - removeRenderer(r); - else - qDebug() << "Could not delete renderer, it might have already been removed:" << call->dringId(); - - // remove the connection from this call to this - disconnect(call, &Call::isOver, this, 0); - } -} - -#else - -/* We use the previous implementation of VideoRendererManager for Windows -systems because the new causes segfault on camera stop. -This is a highly sensible code modify with caution. */ - -void VideoRendererManagerPrivate::removeRenderer(Video::Renderer* r) -{ - if (!r || !m_hRenderers.contains(m_hRendererIds[r])) - return; - - const QByteArray id = m_hRendererIds[r]; - - //Quit if for some reasons the renderer is not found - if ( !r ) { - qWarning() << "Cannot stop rendering, renderer" << id << "not found"; - return; - } - r->stopRendering(); - - qDebug() << "Video stopped for call" << id << "Renderer found:" << m_hRenderers.contains(id); - - Video::Device* dev = Video::DeviceModel::instance().getDevice(id); - - if (dev) - emit dev->renderingStopped(r); - - if (id == PREVIEW_RENDERER_ID) { - m_PreviewState = false; - emit q_ptr->previewStateChanged(false); - emit q_ptr->previewStopped(r); - } - - QThread* t = m_hThreads[r]; - - if (t) { - t->quit(); - t->wait(); - } - - m_hRendererIds.remove(r); - m_hRenderers.remove(id); - - m_hThreads[r] = nullptr; - if (t) { - t->deleteLater(); - } - - r->deleteLater(); -} - -void VideoRendererManagerPrivate::stoppedDecoding(const QString& id, const QString& shmPath) -{ - Q_UNUSED(shmPath) - - if (m_hRenderers.contains(id.toLatin1())) { - removeRenderer(m_hRenderers[id.toLatin1()]); - } -} - -//The moc is generated before preprocessing so we need an implementation too -void VideoRendererManagerPrivate::callIsOver() {} - -#endif - -void VideoRendererManager::switchDevice(const Video::Device* device) const -{ - VideoManagerInterface& interface = VideoManager::instance(); - interface.switchInput(device->id()); -} - -#include <videorenderermanager.moc> diff --git a/src/private/videorenderermanager.h b/src/private/videorenderermanager.h deleted file mode 100644 index 93eb883776bec849f2569bca1847ba73fcff5e70..0000000000000000000000000000000000000000 --- a/src/private/videorenderermanager.h +++ /dev/null @@ -1,84 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the Lesser GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -#pragma once - -//Base -#include <typedefs.h> -#include <QtCore/QThread> - -//Qt -#include <QtCore/QHash> - -//Ring -#include "video/device.h" -namespace Video { - class Renderer; -} -class Call; -class QMutex; -struct SHMHeader; - - -class VideoRendererManagerPrivate; - -///VideoModel: Video event dispatcher -class VideoRendererManager final : public QObject -{ - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop -public: - //Singleton - static VideoRendererManager& instance(); - - void deactivate(); - void useAVFrame(bool useAVFrame); - - //Getters - bool isPreviewing () const; - Video::Renderer* previewRenderer() ; - int size () const; - - //Helpers - Video::Renderer* getRenderer(const Call* call) const; - Video::Renderer* getRenderer(const std::string& callId) const; - void setBufferSize(uint size); - void switchDevice(const Video::Device* device) const; - -private: - //Constructor - explicit VideoRendererManager(); - virtual ~VideoRendererManager(); - - QScopedPointer<VideoRendererManagerPrivate> d_ptr; - Q_DECLARE_PRIVATE(VideoRendererManager) - - -public Q_SLOTS: - void stopPreview (); - void startPreview(); - -Q_SIGNALS: - ///The preview started/stopped - void previewStateChanged(bool startStop); - void previewStarted(Video::Renderer* renderer); - void previewStopped(Video::Renderer* renderer); - void remotePreviewStarted(const std::string& callId, Video::Renderer* renderer); - -}; diff --git a/src/private/videoresolution_p.h b/src/private/videoresolution_p.h deleted file mode 100644 index 25b4c7c7464b32a7397f4522f393b92b33ba5f82..0000000000000000000000000000000000000000 --- a/src/private/videoresolution_p.h +++ /dev/null @@ -1,33 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -namespace Video { - class Rate; - class Channel; -} - -class VideoResolutionPrivate -{ -public: - //Attributes - QList<Video::Rate*> m_lValidRates; - Video::Rate* m_pCurrentRate; - Video::Channel* m_pChannel; - QSize m_Size; -}; diff --git a/src/qtwrapper/configurationmanager_wrap.h b/src/qtwrapper/configurationmanager_wrap.h index 49bfb04675c9c045541b5779a46a04e6d3bfd4a4..b857f11f2d5413e47190cbdd12e5ead24f2151e4 100644 --- a/src/qtwrapper/configurationmanager_wrap.h +++ b/src/qtwrapper/configurationmanager_wrap.h @@ -525,10 +525,6 @@ public Q_SLOTS: // METHODS DRing::setRecordPath(rec.toStdString()); } - void setShortcuts(MapStringString shortcutsMap) { - DRing::setShortcuts(convertMap(shortcutsMap)); - } - void setVolume(const QString& device, double value) { DRing::setVolume(device.toStdString(), value); } diff --git a/src/ringdevicemodel.cpp b/src/ringdevicemodel.cpp deleted file mode 100644 index 9c39db30235284d0a4ddeb2d475df7ccc26ad5c0..0000000000000000000000000000000000000000 --- a/src/ringdevicemodel.cpp +++ /dev/null @@ -1,139 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2016-2019 Savoir-faire Linux Inc. * - * Author : Alexandre Viau <alexandre.viau@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "ringdevice.h" -#include "ringdevicemodel.h" -#include "private/ringdevicemodel_p.h" - -#include "dbus/configurationmanager.h" - -//Qt -#include <QtCore/QDir> -#include <QtCore/QFile> -#include <QtCore/QDirIterator> -#include <QtCore/QJsonDocument> -#include <QtCore/QJsonArray> -#include <QtCore/QJsonObject> -#include <QtCore/QStandardPaths> - -//Ring daemon -#include <account_const.h> - -//Ring -#include "account.h" - -RingDeviceModelPrivate::RingDeviceModelPrivate(RingDeviceModel* q,Account* a) : q_ptr(q),m_pAccount(a) -{ -} - -void RingDeviceModelPrivate::clearLines() -{ - q_ptr->beginRemoveRows(QModelIndex(),0,m_lRingDevices.size()); - qDeleteAll(m_lRingDevices); - m_lRingDevices.clear(); - q_ptr->endRemoveRows(); -} - -void RingDeviceModelPrivate::reload() -{ - const MapStringString accountDevices = ConfigurationManager::instance().getKnownRingDevices(this->m_pAccount->id()); - reload(accountDevices); -} - -void RingDeviceModelPrivate::reload(MapStringString accountDevices) -{ - clearLines(); - - QMapIterator<QString, QString> i(accountDevices); - while (i.hasNext()) { - i.next(); - - RingDevice* device = new RingDevice(i.key(), i.value()); - - q_ptr->beginInsertRows(QModelIndex(),m_lRingDevices.size(), m_lRingDevices.size()); - m_lRingDevices << device; - q_ptr->endInsertRows(); - } -} - -RingDeviceModel::RingDeviceModel(Account* a) : QAbstractTableModel(a), d_ptr(new RingDeviceModelPrivate(this,a)) -{ - d_ptr->reload(); -} - -RingDeviceModel::~RingDeviceModel() -{ - d_ptr->clearLines(); - delete d_ptr; -} - -QVariant RingDeviceModel::data( const QModelIndex& index, int role) const -{ - Q_UNUSED(role); - - if (role == Qt::DisplayRole && index.isValid()) { - - RingDevice* device = nullptr; - if (index.row() < d_ptr->m_lRingDevices.size()) - device = d_ptr->m_lRingDevices[index.row()]; - - if (!device) - return QVariant(); - - return device->columnData(index.column()); - } else - return QVariant(); -} - -QVariant RingDeviceModel::headerData( int section, Qt::Orientation ori, int role) const -{ - if (role == Qt::DisplayRole) { - if (ori == Qt::Vertical) - return section; - - switch (section) { - case static_cast<int>(RingDevice::Column::Id): - return tr("ID"); - case static_cast<int>(RingDevice::Column::Name): - return tr("Name"); - default: - return QVariant(); - } - } - return QVariant(); -} - - -int RingDeviceModel::rowCount( const QModelIndex& parent) const -{ - return parent.isValid()?0:d_ptr->m_lRingDevices.size(); -} - -int RingDeviceModel::columnCount( const QModelIndex& parent) const -{ - return parent.isValid()?0:2; -} - -int RingDeviceModel::size() const -{ - return d_ptr->m_lRingDevices.size(); -} - -Qt::ItemFlags RingDeviceModel::flags(const QModelIndex &index) const -{ - return index.isValid() ? (Qt::ItemIsEnabled | Qt::ItemIsSelectable) : Qt::NoItemFlags; -} diff --git a/src/securityevaluationmodel.cpp b/src/securityevaluationmodel.cpp deleted file mode 100644 index 255d8a38a09f2101a018ab9955cbaaa94cb3cfa4..0000000000000000000000000000000000000000 --- a/src/securityevaluationmodel.cpp +++ /dev/null @@ -1,815 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "securityevaluationmodel.h" - -//Qt -#include <QtCore/QIdentityProxyModel> -#include <QtCore/QTimer> - -//Ring -#include "account.h" -#include "certificatemodel.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "private/securityevaluationmodel_p.h" -#include "securityflaw.h" -#include "private/securityflaw_p.h" -#include "private/certificate_p.h" - -#include <QtAlgorithms> - -const QString SecurityEvaluationModelPrivate::messages[enum_class_size<SecurityEvaluationModel::AccountSecurityChecks>()] = { - /*SRTP_ENABLED */QObject::tr("Your media streams are not encrypted, please enable SDES"), - /*TLS_ENABLED */QObject::tr("TLS is disabled, the negotiation won't be encrypted. Your communication will be vulnerable to " - "snooping"), - /*CERTIFICATE_MATCH */QObject::tr("Your certificate and authority don't match, if your certificate require an authority, it won't work"), - /*OUTGOING_SERVER_MATCH */QObject::tr("The outgoing server specified doesn't match the hostname or the one included in the certificate"), - /*VERIFY_INCOMING_ENABLED */QObject::tr("The \"verify incoming certificate\" option is disabled, this leave you vulnerable to man in the middle attack"), - /*VERIFY_ANSWER_ENABLED */QObject::tr("The \"verify answer certificate\" option is disabled, this leave you vulnerable to man in the middle attack"), - /*REQUIRE_CERTIFICATE_ENABLED */QObject::tr("None of your certificate provide a private key, this is required. Please select a private key" - " or use a certificate with one built-in"), - /* NOT_MISSING_CERTIFICATE */QObject::tr("No certificate has been provided. This is, for now, unsupported by Ring"), - /* NOT_MISSING_AUTHORITY */QObject::tr("No certificate authority is provided, it won't be possible to validate if the answer certificates are valid. Some account may also not work."), -}; - -static const QString s1 = QObject::tr("Your certificate is expired, please contact your system administrator."); -static const QString s2 = QObject::tr("Your certificate is self signed. This break the chain of trust."); - -const TypedStateMachine< SecurityEvaluationModel::SecurityLevel , SecurityEvaluationModel::AccountSecurityChecks > -SecurityEvaluationModelPrivate::maximumSecurityLevel = {{ - /* SRTP_ENABLED */ SecurityEvaluationModel::SecurityLevel::NONE , - /* TLS_ENABLED */ SecurityEvaluationModel::SecurityLevel::NONE , - /* CERTIFICATE_MATCH */ SecurityEvaluationModel::SecurityLevel::WEAK , - /* OUTGOING_SERVER_MATCH */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* VERIFY_INCOMING_ENABLED */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* VERIFY_ANSWER_ENABLED */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* REQUIRE_CERTIFICATE_ENABLED */ SecurityEvaluationModel::SecurityLevel::WEAK , - /* NOT_MISSING_CERTIFICATE */ SecurityEvaluationModel::SecurityLevel::WEAK , - /* NOT_MISSING_AUTHORITY */ SecurityEvaluationModel::SecurityLevel::ACCEPTABLE , -}}; - -const TypedStateMachine< SecurityEvaluationModel::Severity , SecurityEvaluationModel::AccountSecurityChecks > -SecurityEvaluationModelPrivate::flawSeverity = {{ - /* SRTP_ENABLED */ SecurityEvaluationModel::Severity::ISSUE , - /* TLS_ENABLED */ SecurityEvaluationModel::Severity::ISSUE , - /* CERTIFICATE_MATCH */ SecurityEvaluationModel::Severity::ERROR , - /* OUTGOING_SERVER_MATCH */ SecurityEvaluationModel::Severity::WARNING , - /* VERIFY_INCOMING_ENABLED */ SecurityEvaluationModel::Severity::ISSUE , - /* VERIFY_ANSWER_ENABLED */ SecurityEvaluationModel::Severity::ISSUE , - /* REQUIRE_CERTIFICATE_ENABLED */ SecurityEvaluationModel::Severity::ISSUE , - /* NOT_MISSING_CERTIFICATE */ SecurityEvaluationModel::Severity::WARNING , - /* NOT_MISSING_AUTHORITY */ SecurityEvaluationModel::Severity::INFORMATION , -}}; - -const TypedStateMachine< SecurityEvaluationModel::SecurityLevel , Certificate::Checks > SecurityEvaluationModelPrivate::maximumCertificateSecurityLevel = {{ - /* HAS_PRIVATE_KEY */ SecurityEvaluationModel::SecurityLevel::NONE , - /* EXPIRED */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* STRONG_SIGNING */ SecurityEvaluationModel::SecurityLevel::WEAK , - /* NOT_SELF_SIGNED */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* KEY_MATCH */ SecurityEvaluationModel::SecurityLevel::NONE , - /* PRIVATE_KEY_STORAGE_PERMISSION */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* PUBLIC_KEY_STORAGE_PERMISSION */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* PRIVATE_KEY_DIRECTORY_PERMISSIONS */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* PUBLIC_KEY_DIRECTORY_PERMISSIONS */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* PRIVATE_KEY_STORAGE_LOCATION */ SecurityEvaluationModel::SecurityLevel::ACCEPTABLE , - /* PUBLIC_KEY_STORAGE_LOCATION */ SecurityEvaluationModel::SecurityLevel::ACCEPTABLE , - /* PRIVATE_KEY_SELINUX_ATTRIBUTES */ SecurityEvaluationModel::SecurityLevel::ACCEPTABLE , - /* PUBLIC_KEY_SELINUX_ATTRIBUTES */ SecurityEvaluationModel::SecurityLevel::ACCEPTABLE , - /* EXIST */ SecurityEvaluationModel::SecurityLevel::NONE , - /* VALID */ SecurityEvaluationModel::SecurityLevel::NONE , - /* VALID_AUTHORITY */ SecurityEvaluationModel::SecurityLevel::MEDIUM , - /* KNOWN_AUTHORITY */ SecurityEvaluationModel::SecurityLevel::ACCEPTABLE , //TODO figure out of the impact of this - /* NOT_REVOKED */ SecurityEvaluationModel::SecurityLevel::WEAK , - /* AUTHORITY_MATCH */ SecurityEvaluationModel::SecurityLevel::NONE , - /* EXPECTED_OWNER */ SecurityEvaluationModel::SecurityLevel::MEDIUM , //TODO figure out of the impact of this - /* ACTIVATED */ SecurityEvaluationModel::SecurityLevel::MEDIUM , //TODO figure out of the impact of this -}}; - -static const Matrix1D<Certificate::Checks, bool> relevantWithoutPrivateKey = { - { Certificate::Checks::HAS_PRIVATE_KEY , false }, - { Certificate::Checks::EXPIRED , true }, - { Certificate::Checks::STRONG_SIGNING , true }, - { Certificate::Checks::NOT_SELF_SIGNED , true }, - { Certificate::Checks::KEY_MATCH , false }, - { Certificate::Checks::PRIVATE_KEY_STORAGE_PERMISSION , true }, - { Certificate::Checks::PUBLIC_KEY_STORAGE_PERMISSION , true }, - { Certificate::Checks::PRIVATE_KEY_DIRECTORY_PERMISSIONS, true }, - { Certificate::Checks::PUBLIC_KEY_DIRECTORY_PERMISSIONS , true }, - { Certificate::Checks::PRIVATE_KEY_STORAGE_LOCATION , true }, - { Certificate::Checks::PUBLIC_KEY_STORAGE_LOCATION , true }, - { Certificate::Checks::PRIVATE_KEY_SELINUX_ATTRIBUTES , true }, - { Certificate::Checks::PUBLIC_KEY_SELINUX_ATTRIBUTES , true }, - { Certificate::Checks::EXIST , true }, - { Certificate::Checks::VALID , true }, - { Certificate::Checks::VALID_AUTHORITY , true }, - { Certificate::Checks::KNOWN_AUTHORITY , true }, - { Certificate::Checks::NOT_REVOKED , true }, - { Certificate::Checks::AUTHORITY_MATCH , true }, - { Certificate::Checks::EXPECTED_OWNER , true }, - { Certificate::Checks::ACTIVATED , true }, -}; - -const TypedStateMachine< SecurityEvaluationModel::Severity , Certificate::Checks > SecurityEvaluationModelPrivate::certificateFlawSeverity = {{ - /* HAS_PRIVATE_KEY */ SecurityEvaluationModel::Severity::ERROR , - /* EXPIRED */ SecurityEvaluationModel::Severity::WARNING , - /* STRONG_SIGNING */ SecurityEvaluationModel::Severity::ISSUE , - /* NOT_SELF_SIGNED */ SecurityEvaluationModel::Severity::WARNING , - /* KEY_MATCH */ SecurityEvaluationModel::Severity::ERROR , - /* PRIVATE_KEY_STORAGE_PERMISSION */ SecurityEvaluationModel::Severity::WARNING , - /* PUBLIC_KEY_STORAGE_PERMISSION */ SecurityEvaluationModel::Severity::WARNING , - /* PRIVATE_KEY_DIRECTORY_PERMISSIONS */ SecurityEvaluationModel::Severity::WARNING , - /* PUBLIC_KEY_DIRECTORY_PERMISSIONS */ SecurityEvaluationModel::Severity::WARNING , - /* PRIVATE_KEY_STORAGE_LOCATION */ SecurityEvaluationModel::Severity::INFORMATION , - /* PUBLIC_KEY_STORAGE_LOCATION */ SecurityEvaluationModel::Severity::INFORMATION , - /* PRIVATE_KEY_SELINUX_ATTRIBUTES */ SecurityEvaluationModel::Severity::INFORMATION , - /* PUBLIC_KEY_SELINUX_ATTRIBUTES */ SecurityEvaluationModel::Severity::INFORMATION , - /* EXIST */ SecurityEvaluationModel::Severity::ERROR , - /* VALID */ SecurityEvaluationModel::Severity::ERROR , - /* VALID_AUTHORITY */ SecurityEvaluationModel::Severity::WARNING , - /* KNOWN_AUTHORITY */ SecurityEvaluationModel::Severity::WARNING , - /* NOT_REVOKED */ SecurityEvaluationModel::Severity::ISSUE , - /* AUTHORITY_MATCH */ SecurityEvaluationModel::Severity::ISSUE , - /* EXPECTED_OWNER */ SecurityEvaluationModel::Severity::WARNING , - /* ACTIVATED */ SecurityEvaluationModel::Severity::WARNING , -}}; - - -/** - * This class add a prefix in front of Qt::DisplayRole to add a disambiguation - * when there is multiple certificates in the same SecurityEvaluationModel and - * also add new roles such as the severity, BackgroundRole and DecorationRole - */ -class PrefixAndSeverityProxyModel : public QIdentityProxyModel -{ - Q_OBJECT - -public: - - explicit PrefixAndSeverityProxyModel(const QString& prefix,QAbstractItemModel* parent); - - virtual QModelIndex index ( int row , int column, const QModelIndex& parent ) const override; - virtual QVariant data ( const QModelIndex& index , int role ) const override; - virtual int columnCount ( const QModelIndex& parent ) const override; - - //Attributes - QString m_Name; -}; - -/** - * This model transform accounts attributes into security checks to validate if - * some options reduce the security level. - */ -class AccountChecksModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - - enum class Columns { - MESSAGE , - SOURCE , - RESULT , - COUNT__ - }; - - AccountChecksModel(const Account* a); - - //Model functions - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - //Helpers - void update(); - -private: - //Attributes - const Account* m_pAccount; - Matrix1D<SecurityEvaluationModel::AccountSecurityChecks, Certificate::CheckValues> m_lCachedResults; -}; - -/** - * This model take multiple listModels and append them one after the other - * - * the trick for high performance is to known at compile time the sizes - */ -class CombinaisonProxyModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - explicit CombinaisonProxyModel( QAbstractItemModel* publicCert , - QAbstractItemModel* caCert , - QAbstractItemModel* account , - QObject* parent - ); - - //Model functions - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual int columnCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - -private: - //Attributes - QVector<QAbstractItemModel*> m_lSources; - - ///All source model, in order - enum Src { - CA = 0, /*!< Rows allocated for the certificate authority */ - PK = 1, /*!< Rows allocated for the public certificate */ - AC = 2, /*!< Rows allocated for the account settions */ - ER = 3, /*!< TODO Rows allocated for runtime error */ - }; - - ///This model expect a certain size, get each sections size - constexpr static const int sizes[] = { - enum_class_size< Certificate :: Checks > (), - enum_class_size< Certificate :: Checks > (), - enum_class_size< SecurityEvaluationModel :: AccountSecurityChecks > (), - }; - - ///Get the combined size - constexpr inline static int totalSize() { - return sizes[CA] + sizes[PK] + sizes[AC]+1; - } - - ///Get a model index from a value - constexpr inline static int toModelIdx(const int value) { - return (value >= sizes[CA] + sizes[PK] ? AC : ( - value >= sizes[PK] ? PK : - CA ) ); - } - - //Compute the correct index.row() offset - constexpr inline static int fromFinal(const int value) { - return (value >= sizes[CA] + sizes[PK] ? value - sizes[CA] - sizes[PK] : ( - value >= sizes[PK] ? value - sizes[CA] : - value ) ); - } - -}; - -constexpr const int CombinaisonProxyModel::sizes[]; - -///Create a callback map for signals to avoid a large switch(){} in the code -static const Matrix1D<SecurityEvaluationModel::Severity, void(SecurityEvaluationModel::*)()> m_lSignalMap = {{ - /* UNSUPPORTED */ nullptr , - /* INFORMATION */ &SecurityEvaluationModel::informationCountChanged , - /* WARN1NG */ &SecurityEvaluationModel::warningCountChanged , - /* ISSUE */ &SecurityEvaluationModel::issueCountChanged , - /* ERROR */ &SecurityEvaluationModel::errorCountChanged , - /* FATAL_WARNING */ &SecurityEvaluationModel::fatalWarningCountChanged, -}}; - -SecurityEvaluationModelPrivate::SecurityEvaluationModelPrivate(Account* account, SecurityEvaluationModel* parent) : - QObject(parent),q_ptr(parent), m_pAccount(account),m_isScheduled(false), - m_CurrentSecurityLevel(SecurityEvaluationModel::SecurityLevel::NONE),m_pAccChecks(nullptr), - m_SeverityCount{ - /* UNSUPPORTED */ 0, - /* INFORMATION */ 0, - /* WARN1NG */ 0, - /* ISSUE */ 0, - /* ERROR */ 0, - /* FATAL_WARNING */ 0, - } -{ - //Make sure the security level is updated if something change - QObject::connect(parent,&SecurityEvaluationModel::layoutChanged , this,&SecurityEvaluationModelPrivate::update); - QObject::connect(parent,&SecurityEvaluationModel::dataChanged , this,&SecurityEvaluationModelPrivate::update); - QObject::connect(parent,&SecurityEvaluationModel::rowsInserted , this,&SecurityEvaluationModelPrivate::update); - QObject::connect(parent,&SecurityEvaluationModel::rowsRemoved , this,&SecurityEvaluationModelPrivate::update); - QObject::connect(parent,&SecurityEvaluationModel::modelReset , this,&SecurityEvaluationModelPrivate::update); -} - - - -/******************************************************************************* - * * - * PrefixAndSeverityProxyModel * - * * - ******************************************************************************/ - -PrefixAndSeverityProxyModel::PrefixAndSeverityProxyModel(const QString& prefix, QAbstractItemModel* parent) : - QIdentityProxyModel(parent),m_Name(prefix) -{ - setSourceModel(parent); -} - -///It insert a second column with the source name -int PrefixAndSeverityProxyModel::columnCount( const QModelIndex& parent) const -{ - Q_UNUSED(parent) - return parent.isValid() ? 0 : 3; -} - -QModelIndex PrefixAndSeverityProxyModel::index( int row, int column, const QModelIndex& parent) const -{ - if (column == 2) - return createIndex(row,column); - return QIdentityProxyModel::index(row,column,parent); -} - -///Map items and add elements -QVariant PrefixAndSeverityProxyModel::data(const QModelIndex& index, int role) const -{ - if (index.isValid()) { - - Certificate::Checks c = Certificate::Checks::HAS_PRIVATE_KEY; - if (QIdentityProxyModel::data(index,(int)CertificateModel::Role::isCheck).toBool() == true) - c = qvariant_cast<Certificate::Checks>(QIdentityProxyModel::data(index,(int)CertificateModel::Role::check)); - else if (index.column() != 2) //That column doesn't exist in the source, the won't exist - return QVariant(); - - switch (index.column()) { - case (int)AccountChecksModel::Columns::MESSAGE: - switch(role) { - case Qt::DecorationRole: - return GlobalInstances::pixmapManipulator().securityIssueIcon(index); - case (int)SecurityEvaluationModel::Role::Severity: - return QVariant::fromValue(SecurityEvaluationModelPrivate::certificateFlawSeverity[c]); - case (int)SecurityEvaluationModel::Role::SecurityLevel: - return QVariant::fromValue(SecurityEvaluationModelPrivate::maximumCertificateSecurityLevel[c]); - } - break; - // - case (int)AccountChecksModel::Columns::SOURCE: { - switch(role) { - case Qt::DisplayRole: - return m_Name; - case (int)SecurityEvaluationModel::Role::Severity: - return QVariant::fromValue(SecurityEvaluationModelPrivate::certificateFlawSeverity[c]); - case (int)SecurityEvaluationModel::Role::SecurityLevel: - return QVariant::fromValue(SecurityEvaluationModelPrivate::maximumCertificateSecurityLevel[c]); - } - return QVariant(); - } - break; - //Map source column 1 to 2 - case (int)AccountChecksModel::Columns::RESULT: { - const QModelIndex& srcIdx = sourceModel()->index(index.row(),1); - c = qvariant_cast<Certificate::Checks>(srcIdx.data((int)CertificateModel::Role::check)); - - switch(role) { - case (int)SecurityEvaluationModel::Role::Severity: - return QVariant::fromValue(SecurityEvaluationModelPrivate::certificateFlawSeverity[c]); - case (int)SecurityEvaluationModel::Role::SecurityLevel: - return QVariant::fromValue(SecurityEvaluationModelPrivate::maximumCertificateSecurityLevel[c]); - } - - return srcIdx.data(role); - } - } - } - - return QIdentityProxyModel::data(index,role); -} - - - -/******************************************************************************* - * * - * AccountChecksModel * - * * - ******************************************************************************/ - -AccountChecksModel::AccountChecksModel(const Account* a) : QAbstractTableModel(const_cast<Account*>(a)), m_pAccount(a) -{ - update(); -} - -QVariant AccountChecksModel::data( const QModelIndex& index, int role ) const -{ - if ((!index.isValid()) - || (index.row() < 0) - || (index.row() >= enum_class_size<SecurityEvaluationModel::AccountSecurityChecks>()) - ) - return QVariant(); - - const SecurityEvaluationModel::AccountSecurityChecks f = static_cast<SecurityEvaluationModel::AccountSecurityChecks>(index.row()); - - switch(role) { - case (int)SecurityEvaluationModel::Role::Severity: - return QVariant::fromValue( - m_lCachedResults[f] == Certificate::CheckValues::UNSUPPORTED ? - SecurityEvaluationModel::Severity::UNSUPPORTED : SecurityEvaluationModelPrivate::flawSeverity[f] - ); - case (int)SecurityEvaluationModel::Role::SecurityLevel: - return QVariant::fromValue( - //If the check is unsupported then using "COMPLETE" won't affect the algorithm output - // if n < current then n else current end will always be "current" when n == maximum - m_lCachedResults[f] == Certificate::CheckValues::UNSUPPORTED ? - SecurityEvaluationModel::SecurityLevel::COMPLETE : SecurityEvaluationModelPrivate::maximumSecurityLevel[f] - ); - } - - switch (index.column()) { - case (int)AccountChecksModel::Columns::MESSAGE: - switch(role) { - case Qt::DisplayRole: - return SecurityEvaluationModelPrivate::messages[index.row()]; - case Qt::DecorationRole: - return GlobalInstances::pixmapManipulator().securityIssueIcon(index); - }; - break; - case (int)AccountChecksModel::Columns::SOURCE: - switch(role) { - case Qt::DisplayRole: - return tr("Configuration"); - }; - break; - case (int)AccountChecksModel::Columns::RESULT: - switch(role) { - case Qt::DisplayRole: - if (m_lCachedResults[f] != Certificate::CheckValues::UNSUPPORTED) - return m_lCachedResults[f] == Certificate::CheckValues::PASSED ? true : false; - break; - }; - break; - }; - - return QVariant(); -} - -int AccountChecksModel::rowCount( const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : enum_class_size<SecurityEvaluationModel::AccountSecurityChecks>(); -} - -int AccountChecksModel::columnCount( const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : enum_class_size<AccountChecksModel::Columns>(); -} - -Qt::ItemFlags AccountChecksModel::flags( const QModelIndex& index) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -bool AccountChecksModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role ) - return false; -} - -QHash<int,QByteArray> AccountChecksModel::roleNames() const -{ - return {}; -} - -//This could have been an inlined function too -#define SET_CHECK_VALUE(check,condition) {Certificate::CheckValues c = Certificate::CheckValues::UNSUPPORTED;\ - bool isSet = m_lCachedResults.isSet(check); if (isSet) c = m_lCachedResults[check]; m_lCachedResults.setAt( check ,\ - condition? Certificate::CheckValues::PASSED : Certificate::CheckValues::FAILED);\ - changed |= (!isSet) || c != m_lCachedResults[check];} - -void AccountChecksModel::update() -{ - bool changed = false; - - // AccountSecurityChecks::SRTP_DISABLED - SET_CHECK_VALUE(SecurityEvaluationModel::AccountSecurityChecks::SRTP_ENABLED , - m_pAccount->isSrtpEnabled () || m_pAccount->protocol() == Account::Protocol::RING - ); - - // AccountSecurityChecks::TLS_DISABLED - SET_CHECK_VALUE( SecurityEvaluationModel::AccountSecurityChecks::TLS_ENABLED , - m_pAccount->isTlsEnabled () - ); - - // AccountSecurityChecks::CERTIFICATE_MISMATCH - m_lCachedResults.setAt( SecurityEvaluationModel::AccountSecurityChecks::CERTIFICATE_MATCH , - Certificate::CheckValues::UNSUPPORTED); //TODO - - // AccountSecurityChecks::OUTGOING_SERVER_MISMATCH - m_lCachedResults.setAt( SecurityEvaluationModel::AccountSecurityChecks::OUTGOING_SERVER_MATCH , - Certificate::CheckValues::UNSUPPORTED); //TODO - - // AccountSecurityChecks::VERIFY_INCOMING_DISABLED - SET_CHECK_VALUE( SecurityEvaluationModel::AccountSecurityChecks::VERIFY_INCOMING_ENABLED , - m_pAccount->isTlsVerifyServer () - ); - - // AccountSecurityChecks::VERIFY_ANSWER_DISABLED - SET_CHECK_VALUE( SecurityEvaluationModel::AccountSecurityChecks::VERIFY_ANSWER_ENABLED , - m_pAccount->isTlsVerifyClient () - ); - - // AccountSecurityChecks::REQUIRE_CERTIFICATE_DISABLED - SET_CHECK_VALUE( SecurityEvaluationModel::AccountSecurityChecks::REQUIRE_CERTIFICATE_ENABLED , - m_pAccount->isTlsRequireClientCertificate() - ); - - // AccountSecurityChecks::MISSING_CERTIFICATE - SET_CHECK_VALUE( SecurityEvaluationModel::AccountSecurityChecks::NOT_MISSING_CERTIFICATE , - m_pAccount->tlsCertificate () - ); - - // AccountSecurityChecks::MISSING_AUTHORITY - SET_CHECK_VALUE( SecurityEvaluationModel::AccountSecurityChecks::NOT_MISSING_AUTHORITY , - m_pAccount->tlsCaListCertificate () - ); - - if (changed) - emit dataChanged(index(0,2),index(rowCount()-1,2)); -} -#undef SET_CHECK_VALUE - - -/******************************************************************************* - * * - * CombinaisonProxyModel * - * * - ******************************************************************************/ - -CombinaisonProxyModel::CombinaisonProxyModel(QAbstractItemModel* publicCert, - QAbstractItemModel* caCert , - QAbstractItemModel* account , - QObject* parent ) - : QAbstractTableModel(parent), m_lSources({publicCert,caCert,account}) -{ - for (int i = 0; i < m_lSources.size(); i++) { - const QAbstractItemModel* m = m_lSources[i]; - if (m) { - connect(m, &QAbstractItemModel::dataChanged, [this,i](const QModelIndex& tl, const QModelIndex& br) { - - int offset =0; - for (int j = 0; j < i;j++) - offset += sizes[j]; - - - emit this->dataChanged(this->index(offset+tl.row(), br.column()), this->index(offset+br.row(), br.column())); - }); - } - } -} - -QVariant CombinaisonProxyModel::data( const QModelIndex& index, int role) const -{ - const QAbstractItemModel* src = m_lSources[toModelIdx(index.row())]; - - //Role::Severity will give ::UNSUPPORTED (aka, 0) if a model is missing - //this is done on purpose - - //All "groups" will have empty items for unsupported checks - - return index.isValid() && src ? src->index(fromFinal(index.row()),index.column()).data(role) : QVariant(); -} - -int CombinaisonProxyModel::rowCount( const QModelIndex& parent) const -{ - return parent.isValid() ? 0 : totalSize(); -} - -int CombinaisonProxyModel::columnCount( const QModelIndex& parent) const -{ - return parent.isValid() ? 0 : 3; -} - -Qt::ItemFlags CombinaisonProxyModel::flags( const QModelIndex& index) const -{ - Q_UNUSED(index) - return Qt::ItemIsEnabled | Qt::ItemIsSelectable; -} - -bool CombinaisonProxyModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role ) - return false; -} - -QHash<int,QByteArray> CombinaisonProxyModel::roleNames() const -{ - return {}; -} - - - -/******************************************************************************* - * * - * SecurityEvaluationModel * - * * - ******************************************************************************/ - -SecurityEvaluationModel::SecurityEvaluationModel(Account* account) : QSortFilterProxyModel(account), -d_ptr(new SecurityEvaluationModelPrivate(account,this)) -{ - Certificate* caCert = d_ptr->m_pAccount->tlsCaListCertificate (); - Certificate* pkCert = d_ptr->m_pAccount->tlsCertificate (); - - SecurityEvaluationModelPrivate::getCertificateSeverityProxy(caCert); - SecurityEvaluationModelPrivate::getCertificateSeverityProxy(pkCert); - - d_ptr->m_pAccChecks = new AccountChecksModel(account); - - d_ptr->update(); - - setSourceModel(new CombinaisonProxyModel(pkCert ? pkCert->d_ptr->m_pSeverityProxy : nullptr, caCert ? caCert->d_ptr->m_pSeverityProxy : nullptr, d_ptr->m_pAccChecks,this)); - - setSortRole((int)Role::Severity); -} - -SecurityEvaluationModel::~SecurityEvaluationModel() -{ - delete d_ptr; -} - -bool SecurityEvaluationModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const -{ - const QModelIndex& idx = sourceModel()->index(source_row,0,source_parent); - const QModelIndex& idx2 = sourceModel()->index(source_row,2,source_parent); - const Severity s = qvariant_cast<Severity>(idx.data((int)SecurityEvaluationModel::Role::Severity)); - return s != Severity::UNSUPPORTED && idx2.data(Qt::DisplayRole).toBool() == false; -} - -QHash<int,QByteArray> SecurityEvaluationModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles[(int)Role::Severity] = "Severity"; - } - return roles; -} - -void SecurityEvaluationModelPrivate::update() -{ - //As this can be called multiple time, only perform the checks once per event loop cycle - if (!m_isScheduled) { - m_pAccChecks->update(); - -#if QT_VERSION >= 0x050400 - QTimer::singleShot(0,this,&SecurityEvaluationModelPrivate::updateReal); - m_isScheduled = true; -#else //Too bad for Qt < 5.3 users - updateReal(); -#endif - - } -} - -QAbstractItemModel* SecurityEvaluationModelPrivate::getCertificateSeverityProxy(Certificate* c) -{ - if (!c) - return nullptr; - - if (!c->d_ptr->m_pSeverityProxy) - c->d_ptr->m_pSeverityProxy = new PrefixAndSeverityProxyModel(tr("Authority" ),c->checksModel()); - - return c->d_ptr->m_pSeverityProxy; -} - -SecurityEvaluationModel::SecurityLevel SecurityEvaluationModelPrivate::maxSecurityLevel(QAbstractItemModel* m, int* counter) -{ - typedef SecurityEvaluationModel::Severity Severity ; - typedef SecurityEvaluationModel::SecurityLevel SecurityLevel; - - SecurityLevel maxLevel = SecurityLevel::COMPLETE; - - for (int i=0; i < m->rowCount();i++) { - const QModelIndex& idx = m->index(i,0); - - const Severity severity = qvariant_cast<Severity>( - idx.data((int) SecurityEvaluationModel::Role::Severity) - ); - - //Ignore items without severity - const QVariant levelVariant = idx.data((int) SecurityEvaluationModel::Role::SecurityLevel ); - - const SecurityLevel level = levelVariant.canConvert<SecurityLevel>() ? qvariant_cast<SecurityLevel>( - levelVariant - ) : maxLevel; - - //Increment the count - if (counter) - counter[static_cast<int>(severity)]++; - - const bool forceIgnore = idx.data((int)CertificateModel::Role::requirePrivateKey).toBool(); - - //Update the maximum level - maxLevel = level < maxLevel && !forceIgnore ? level : maxLevel; - } - - return maxLevel; -} - -void SecurityEvaluationModelPrivate::updateReal() -{ - typedef SecurityEvaluationModel::Severity Severity ; - typedef SecurityEvaluationModel::SecurityLevel SecurityLevel; - - int countCache[enum_class_size<SecurityEvaluationModel::Severity>()] = {}; - - //Reset the counter - for (const Severity s : EnumIterator<Severity>()) { - countCache [(int)s] = m_SeverityCount[(int)s]; - m_SeverityCount[(int)s] = 0 ; - } - - SecurityLevel maxLevel = maxSecurityLevel(q_ptr, m_SeverityCount); - - //Notify - for (const Severity s : EnumIterator<Severity>()) { - if (countCache[(int)s] != m_SeverityCount[(int)s] && m_lSignalMap[s]) - (q_ptr->*m_lSignalMap[s])(); - } - - //Update the security level - if (m_CurrentSecurityLevel != maxLevel) { - m_CurrentSecurityLevel = maxLevel; - - emit q_ptr->securityLevelChanged(); - } - - m_isScheduled = false; -} - -QModelIndex SecurityEvaluationModel::getIndex(const SecurityFlaw* flaw) -{ - return index(flaw->d_ptr->m_Row,0); -} - -QList<SecurityFlaw*> SecurityEvaluationModel::currentFlaws() -{ - return d_ptr->m_lCurrentFlaws; -} - -SecurityEvaluationModel::SecurityLevel SecurityEvaluationModel::securityLevel() const -{ - return d_ptr->m_CurrentSecurityLevel; -} - -SecurityEvaluationModel::SecurityLevel SecurityEvaluationModelPrivate::certificateSecurityLevel(const Certificate* c, bool forceIgnorePrivateKey) -{ - typedef SecurityEvaluationModel::SecurityLevel SecurityLevel; - - SecurityLevel maxLevelWithPriv = SecurityLevel::COMPLETE; - SecurityLevel maxLevelWithoutPriv = SecurityLevel::COMPLETE; - - const bool ignorePrivateKey = forceIgnorePrivateKey || (c->requirePrivateKey() == false); - - if (c->d_ptr->m_hasLoadedSecurityLevel) { - if (ignorePrivateKey) - return c->d_ptr->m_SecurityLevelWithoutPriv; - else - return c->d_ptr->m_SecurityLevelWithPriv; - } - - for (const Certificate::Checks check : EnumIterator<Certificate::Checks>()) { - const bool relevant = relevantWithoutPrivateKey[check]; - if (c->checkResult(check) == Certificate::CheckValues::FAILED) { - if (relevant) { - const SecurityLevel checkLevel = maximumCertificateSecurityLevel[check]; - maxLevelWithoutPriv = checkLevel < maxLevelWithoutPriv ? checkLevel : maxLevelWithoutPriv; - } - const SecurityLevel checkLevel = maximumCertificateSecurityLevel[check]; - maxLevelWithPriv = checkLevel < maxLevelWithPriv ? checkLevel : maxLevelWithPriv; - } - } - - c->d_ptr->m_hasLoadedSecurityLevel = true; - c->d_ptr->m_SecurityLevelWithoutPriv = maxLevelWithoutPriv; - c->d_ptr->m_SecurityLevelWithPriv = maxLevelWithPriv; - - return ignorePrivateKey ? c->d_ptr->m_SecurityLevelWithoutPriv : c->d_ptr->m_SecurityLevelWithPriv; -} - -//Map the array to getters -int SecurityEvaluationModel::informationCount () const -{ return d_ptr->m_SeverityCount[ (int)Severity::INFORMATION ]; } -int SecurityEvaluationModel::warningCount () const -{ return d_ptr->m_SeverityCount[ (int)Severity::WARNING ]; } -int SecurityEvaluationModel::issueCount () const -{ return d_ptr->m_SeverityCount[ (int)Severity::ISSUE ]; } -int SecurityEvaluationModel::errorCount () const -{ return d_ptr->m_SeverityCount[ (int)Severity::ERROR ]; } -int SecurityEvaluationModel::fatalWarningCount () const -{ return d_ptr->m_SeverityCount[ (int)Severity::FATAL_WARNING ]; } - -#include <securityevaluationmodel.moc> diff --git a/src/securityevaluationmodel.h b/src/securityevaluationmodel.h deleted file mode 100644 index 73c0413c0da88285a5775ad8dea5d8c63288fe59..0000000000000000000000000000000000000000 --- a/src/securityevaluationmodel.h +++ /dev/null @@ -1,164 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QSortFilterProxyModel> - -//Ring -#include "certificate.h" -#include "typedefs.h" - - -//Ring -class Account; -class SecurityFlaw; - -class SecurityEvaluationModelPrivate; - -/** - * This model provide a real time look at elements security. It aggregate data - * from various security related sources, assign a severity and sort them. - * - * It can also generate a summarized report on the asset security. - * - * This use a best effort approach. Not all known or possible attacks are handled - * by this system. Result should be taken with a grain of salt, but at least some - * common problems can be detected. - */ -class LIB_EXPORT SecurityEvaluationModel : public QSortFilterProxyModel { - Q_OBJECT - friend class SecurityFlaw; - friend class AccountPrivate; -public: - /* - * This class evaluate the overall security of an account. - * It does so by checking various potential flaws, then create - * a metric called SecurityLevel. This model should be used to: - * - * 1) List all potential flaws - * 2) Decide if an account can be considered secure - * 3) Decide if a call can be considered secure - * - * End users should not have to be security gurus to setup Ring. It is our - * job to do as much as we can to make security configuration as transparent as - * possible. - * - * The SecurityLevel is computed by checking all possible flaw. The level cannot be - * higher than a flaw maximum security level. If there is 2 (or more) flaw in the same - * maximum level, the maximum level will be decreased by one (recursively). - * - * A flaw severity is used by the client to display the right icon ( (i), /!\, [x] ). - */ - - //Properties - Q_PROPERTY(int informationCount READ informationCount NOTIFY informationCountChanged ) - Q_PROPERTY(int warningCount READ warningCount NOTIFY warningCountChanged ) - Q_PROPERTY(int issueCount READ issueCount NOTIFY issueCountChanged ) - Q_PROPERTY(int errorCount READ errorCount NOTIFY errorCountChanged ) - Q_PROPERTY(int fatalWarningCount READ fatalWarningCount NOTIFY fatalWarningCountChanged ) - Q_PROPERTY(SecurityLevel securityLevel READ securityLevel NOTIFY securityLevelChanged ) - - ///Give the user an overview of the current security state - enum class SecurityLevel { - NONE = 0, /*!< Security is not functional or severely defective */ - WEAK = 1, /*!< There is some security, but way too many flaws */ - MEDIUM = 2, /*!< The security is probably good enough, but there is issues */ - ACCEPTABLE = 3, /*!< The security is most probably good enough, only minor issues */ - STRONG = 4, /*!< All the non-information items are correct */ - COMPLETE = 5, /*!< Everything, even the recommendations, are correct */ - COUNT__, - }; - Q_ENUMS(SecurityLevel) - - ///The severity of a given flaw - enum class Severity { - #pragma push_macro("ERROR") - #undef ERROR - UNSUPPORTED = 0, /*!< This severity is unsupported, to be ignored */ - INFORMATION = 1, /*!< Tip and tricks to have better security */ - WARNING = 2, /*!< It is a problem, but it won't have other side effects */ - ISSUE = 3, /*!< The security is compromised */ - ERROR = 4, /*!< It simply won't work (REGISTER) */ - FATAL_WARNING = 5, /*!< Registration may work, but it render everything else useless */ - COUNT__, - #pragma pop_macro("ERROR") - }; - Q_ENUMS(Severity) - ///Every supported flaws - enum class AccountSecurityChecks { - SRTP_ENABLED , /*!< The account use secure media streams */ - TLS_ENABLED , /*!< The account use secure negotiation */ - CERTIFICATE_MATCH , /*!< The certificate an authority are related */ - OUTGOING_SERVER_MATCH , /*!< The outgoing server match the certificate hostname */ - VERIFY_INCOMING_ENABLED , /*!< The incoming certificates are validated */ - VERIFY_ANSWER_ENABLED , /*!< The answer certificates are validated */ - REQUIRE_CERTIFICATE_ENABLED , /*!< The account require certificates to operate in TLS mode */ - NOT_MISSING_CERTIFICATE , /*!< The certificate is set */ - NOT_MISSING_AUTHORITY , /*!< The certificate authority is set */ - COUNT__ - }; - Q_ENUMS(AccountSecurityChecks) - - ///Role for the model - enum class Role { - Severity = 100, - SecurityLevel = 101, - }; - - ///Source of a security flaw - enum class ChecksSource { - ACCOUNT_CERTIFICATE = 0, /*!< The flaw is induced by the account certificate */ - ACCOUNT_AUTHORITY = 1, /*!< The flaw is induced by the account authority certificate */ - ACCOUNT_SETTINGS = 2, /*!< The flaw is induced by an account misconfiguration */ - ACCOUNT_REGISTRATION = 3, /*!< The flaw has been detected by runtime registration checks */ - CALL_DETAILS = 4, /*!< The flaw has been detected by runtime communication negotiation */ - }; - - //Constructor - explicit SecurityEvaluationModel(Account* account); - virtual ~SecurityEvaluationModel(); - - //Model functions - virtual QHash<int,QByteArray> roleNames() const override; - virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; - - //Getter - QList<SecurityFlaw*> currentFlaws(); - QModelIndex getIndex(const SecurityFlaw* flaw); - int informationCount () const; - int warningCount () const; - int issueCount () const; - int errorCount () const; - int fatalWarningCount() const; - SecurityLevel securityLevel () const; - -Q_SIGNALS: - void informationCountChanged (); - void warningCountChanged (); - void issueCountChanged (); - void errorCountChanged (); - void fatalWarningCountChanged(); - void securityLevelChanged (); - -private: - SecurityEvaluationModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(SecurityEvaluationModel) -}; -Q_DECLARE_METATYPE(SecurityEvaluationModel*) -Q_DECLARE_METATYPE(SecurityEvaluationModel::Severity) -Q_DECLARE_METATYPE(SecurityEvaluationModel::SecurityLevel) diff --git a/src/securityflaw.cpp b/src/securityflaw.cpp deleted file mode 100644 index 86f608adf4f64a7f9611fd82d65b7c631ba515ee..0000000000000000000000000000000000000000 --- a/src/securityflaw.cpp +++ /dev/null @@ -1,63 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2013-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "securityflaw.h" - -//Ring -#include "private/securityevaluationmodel_p.h" -#include "private/securityflaw_p.h" - -SecurityFlawPrivate::SecurityFlawPrivate(SecurityFlaw* parent, SecurityEvaluationModel::AccountSecurityChecks f,Certificate::Type type):m_flaw(f),m_certType(type),m_Row(-1) -,m_severity(SecurityEvaluationModelPrivate::flawSeverity[f]),q_ptr(parent) -{ - -} - -SecurityFlaw::SecurityFlaw(SecurityEvaluationModel::AccountSecurityChecks f,Certificate::Type type) - : QObject(), d_ptr(new SecurityFlawPrivate(this, f, type)) -{ -} - -Certificate::Type SecurityFlaw::type() const -{ - return d_ptr->m_certType; -} - -SecurityEvaluationModel::AccountSecurityChecks SecurityFlaw::flaw() const -{ - return d_ptr->m_flaw; -} - -SecurityEvaluationModel::Severity SecurityFlaw::severity() const -{ - return d_ptr->m_severity; -} - -void SecurityFlaw::requestHighlight() -{ - emit highlight(); -} - -bool SecurityFlaw::operator < ( const SecurityFlaw &r ) const { - return ( (int)d_ptr->m_severity > (int)r.d_ptr->m_severity ); -} - -bool SecurityFlaw::operator > ( const SecurityFlaw &r ) const { - return ( (int)d_ptr->m_severity < (int)r.d_ptr->m_severity ); -} - -#include <securityflaw.moc> diff --git a/src/securityflaw.h b/src/securityflaw.h deleted file mode 100644 index 6628fd3bebefaf76c2d572af239e1d7a6f1628fa..0000000000000000000000000000000000000000 --- a/src/securityflaw.h +++ /dev/null @@ -1,58 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#include <typedefs.h> - -#include <securityevaluationmodel.h> - -class SecurityFlawPrivate; - -///A flaw representation -class LIB_EXPORT SecurityFlaw : public QObject -{ - Q_OBJECT - friend class SecurityEvaluationModel; - friend class SecurityEvaluationModelPrivate; -public: - - //Operators - bool operator < ( const SecurityFlaw &r ) const; - bool operator > ( const SecurityFlaw &r ) const; - - //Getter - Certificate::Type type() const; - SecurityEvaluationModel::AccountSecurityChecks flaw() const; - SecurityEvaluationModel::Severity severity() const; - -private: - explicit SecurityFlaw(SecurityEvaluationModel::AccountSecurityChecks f,Certificate::Type type = Certificate::Type::NONE); - - SecurityFlawPrivate* d_ptr; - Q_DECLARE_PRIVATE(SecurityFlaw) - -public Q_SLOTS: - void requestHighlight(); - -Q_SIGNALS: - void solved(); - void highlight(); -}; - diff --git a/src/shmrenderer.cpp b/src/shmrenderer.cpp index 117cf1486a5fbd6d53d8621f81b202306058f501..5bfa0de43ceb09257728806f32a34cac2d29901c 100644 --- a/src/shmrenderer.cpp +++ b/src/shmrenderer.cpp @@ -40,8 +40,6 @@ #include <QtCore/QTimer> #include <chrono> -#include "private/videorenderermanager.h" -#include "video/resolution.h" #include "private/videorenderer_p.h" // Uncomment following line to output in console the FPS value @@ -181,7 +179,7 @@ bool ShmRendererPrivate::getNewFrame(bool wait) auto& frame_ptr = q_ptr->Video::Renderer::d_ptr->m_pFrame; if (not frame_ptr) - frame_ptr.reset(new Frame); + frame_ptr.reset(new lrc::api::video::Frame); frame_ptr->storage.clear(); frame_ptr->ptr = m_pShmArea->data + m_pShmArea->readOffset; frame_ptr->size = m_pShmArea->frameSize; @@ -367,7 +365,7 @@ int ShmRenderer::fps() const } /// Get frame data pointer from shared memory -Frame ShmRenderer::currentFrame() const +lrc::api::video::Frame ShmRenderer::currentFrame() const { if (not isRendering()) return {}; diff --git a/src/shmrenderer.h b/src/shmrenderer.h index faaebe3a19a2be98042b13763c2ea38ab8ecf473..f0c663d0dcf3f8c22e394f864475fc5c3c29de6a 100644 --- a/src/shmrenderer.h +++ b/src/shmrenderer.h @@ -22,13 +22,11 @@ //Base #include "video/renderer.h" #include "typedefs.h" +#include "api/newvideo.h" //Qt class QMutex; -//Ring -#include "video/device.h" - //Private struct SHMHeader; struct AVFrame; @@ -44,8 +42,6 @@ class LIB_EXPORT ShmRenderer final : public Renderer { Q_OBJECT #pragma GCC diagnostic pop - friend class VideoRendererManagerPrivate ; - public: //Constructor ShmRenderer (const QByteArray& id, const QString& shmPath, const QSize& res); @@ -57,7 +53,7 @@ public: //Getters int fps() const; - virtual Frame currentFrame() const override; + virtual lrc::api::video::Frame currentFrame() const override; virtual ColorSpace colorSpace () const override; //Setters diff --git a/src/shortcutcreatordefault.cpp b/src/shortcutcreatordefault.cpp deleted file mode 100644 index ba1e38dc5f11279f945b3e89a6f705cf3ce23c68..0000000000000000000000000000000000000000 --- a/src/shortcutcreatordefault.cpp +++ /dev/null @@ -1,30 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "shortcutcreatordefault.h" - -#include "macro.h" - -namespace Interfaces { - -QVariant ShortcutCreatorDefault::createAction(Macro* macro) -{ - Q_UNUSED(macro) - return QVariant(); -} - -} // namespace Interfaces diff --git a/src/shortcutcreatordefault.h b/src/shortcutcreatordefault.h deleted file mode 100644 index d457c275332af40a181a0f963a4ac618b28d0c09..0000000000000000000000000000000000000000 --- a/src/shortcutcreatordefault.h +++ /dev/null @@ -1,37 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -//Qt -#include <QtCore/QVariant> - -//Ring -#include "interfaces/shortcutcreatori.h" -class Macro; - -namespace Interfaces { - -///Default implementation of the the ShortcutCreator interfaces; does nothing -class LIB_EXPORT ShortcutCreatorDefault : public ShortcutCreatorI { -public: - QVariant createAction(Macro* macro) override; -}; - -} // namespace Interfaces diff --git a/src/usage_statistics.cpp b/src/usage_statistics.cpp deleted file mode 100644 index ba5c132e18cf3ae3a07700a7d057cc4900349bc9..0000000000000000000000000000000000000000 --- a/src/usage_statistics.cpp +++ /dev/null @@ -1,103 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. * - * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * - * Author : Stepan Salenikovich <stepan.salenikovich@savoirfairelinux.com>* - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "usage_statistics.h" - -//Qt -#include <QDebug> - -//Accessors - -unsigned -UsageStatistics::totalCount() const { - return m_TotalSeconds; -} - -unsigned -UsageStatistics::totalSeconds() const { - return m_TotalSeconds; -} - -unsigned -UsageStatistics::lastWeekCount() const { - return m_LastWeekCount; -} - -unsigned -UsageStatistics::lastTrimCount() const { - return m_LastTrimCount; -} - -time_t -UsageStatistics::lastUsed() const { - return m_LastUsed; -} - -bool -UsageStatistics::haveCalled() const { - return m_HaveCalled; -} - -//Mutators - -void -UsageStatistics::setHaveCalled() { - m_HaveCalled = true; -} - -/// \brief Update usage using a time range. -/// -/// All values are updated using given <tt>[start, stop]</tt> time range. -/// \a start and \a stop are given in seconds. -/// -/// \param start starting time of usage -/// \param stop ending time of usage, must be greater than \a start -void -UsageStatistics::update(const time_t& start, const time_t& stop) { - ++m_TotalCount; - setLastUsed(start); - m_TotalSeconds += stop - start; - time_t now; - ::time(&now); - if (now - 3600*24*7 < stop) - ++m_LastWeekCount; - if (now - 3600*24*7*15 < stop) - ++m_LastTrimCount; -} - -/// \brief Use this method to update lastUsed time by a new time only if sooner. -/// -/// \return \a true if the update has been effective. -bool -UsageStatistics::setLastUsed(time_t new_time) { - if (new_time > m_LastUsed) { - m_LastUsed = new_time; - return true; - } - return false; -} - -UsageStatistics& UsageStatistics::operator+=(const UsageStatistics& rhs) { - m_TotalCount += rhs.m_TotalCount; - m_LastWeekCount += rhs.m_LastWeekCount; - m_LastTrimCount += rhs.m_LastTrimCount; - m_HaveCalled += rhs.m_TotalCount; // '+=' mean '|=' here - setLastUsed(rhs.m_LastUsed); - return *this; -} diff --git a/src/usage_statistics.h b/src/usage_statistics.h deleted file mode 100644 index e79d4912a1562a3d0f06de8b329a0898bbce56ab..0000000000000000000000000000000000000000 --- a/src/usage_statistics.h +++ /dev/null @@ -1,73 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2017-2019 Savoir-faire Linux Inc. * - * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ - -#pragma once - -//Std -#include <time.h> - -/// \brief UsageStatistics is a container to store common statistics about -/// usage of arbitrary object. -class UsageStatistics -{ -public: - //Accessors - - unsigned totalCount() const; - - unsigned totalSeconds() const; - - unsigned lastWeekCount() const; - - unsigned lastTrimCount() const; - - time_t lastUsed() const; - - bool haveCalled() const; - - //Mutators - - void setHaveCalled(); - - /// \brief Update usage using a time range. - /// - /// All values are updated using given <tt>[start, stop]</tt> time range. - /// \a start and \a stop are given in seconds. - /// - /// \param start starting time of usage - /// \param stop ending time of usage, must be greater than \a start - void update(const time_t& start, const time_t& stop); - - /// \brief Use this method to update lastUsed time by a new time only if sooner. - /// - /// \return \a true if the update has been effective. - bool setLastUsed(time_t new_time); - - /// \brief Inplace incrementation of current values by values from another UsageStatistics instance. - /// - /// \note \a lastUsed time is not incremented but updated using setLastUsed(). - UsageStatistics& operator+=(const UsageStatistics& rhs); - -private: - unsigned m_TotalCount {0}; ///< cummulated usage in number of time - unsigned m_TotalSeconds {0}; ///< cummulated usage in number of seconds - unsigned m_LastWeekCount {0}; ///< XXX: not documented, not clear - unsigned m_LastTrimCount {0}; ///< XXX: not documented, not clear - time_t m_LastUsed {0}; ///< last usage time - bool m_HaveCalled {false}; ///< has object been called? (used for call type object) -}; diff --git a/src/useractionmodel.cpp b/src/useractionmodel.cpp deleted file mode 100644 index f0729286507a0a9d7cf6fea227f16acc74e88f8a..0000000000000000000000000000000000000000 --- a/src/useractionmodel.cpp +++ /dev/null @@ -1,1203 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "useractionmodel.h" - -//Qt -#include <QtCore/QItemSelection> -#include <QtCore/QSortFilterProxyModel> - -//Ring -#include "call.h" -#include "mime.h" -#include "callmodel.h" -#include "account.h" -#include "accountmodel.h" -#include "contactmethod.h" -#include "availableaccountmodel.h" -#include "phonedirectorymodel.h" -#include "globalinstances.h" -#include "interfaces/pixmapmanipulatori.h" -#include "interfaces/actionextenderi.h" -#include "private/useractions.h" -#include "private/matrixutils.h" -#include "media/textrecording.h" - -#define UAM UserActionModel - -class ActiveUserActionModel : public QSortFilterProxyModel -{ -public: - ActiveUserActionModel(QAbstractItemModel* parent) : QSortFilterProxyModel(parent) - { - setSourceModel(parent); - } - virtual bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const override; -}; - -class UserActionModelPrivate final : public QObject -{ - Q_OBJECT -public: - enum class SelectionState { - NONE , /*!< No Item is selected */ - UNIQUE, /*!< A single item is selected */ - MULTI , /*!< Multiple items are selected */ - COUNT__, - }; - - enum class UserActionModelMode { - CALL , /*!< Model the react on a single call element */ - GENERIC , /*!< Model that react on a model selection */ - }; - - //Availability matrices - UserActionModelPrivate(UserActionModel* parent, const FlagPack<UAM::Context>& c); - static const Matrix1D< UAM::Action , bool > heterogenous_call_options ; - static const Matrix2D< UAM::Action, Call::State , bool > availableActionMap ; - static const Matrix2D< UAM::Action, Account::RegistrationState, bool > availableAccountActionMap ; - static const Matrix2D< UAM::Action, SelectionState , bool > multi_call_options ; - static const Matrix2D< UAM::Action, Account::Protocol , bool > availableProtocolActions ; - static const Matrix1D< UAM::Action, FlagPack<UAM::Context> > actionContext ; - static const Matrix1D< UAM::Action, FlagPack<UAM::Asset> > availableByAsset ; - static const Matrix2D< UAM::Action, Ring::ObjectType , bool > availableObjectActions ; - static const Matrix1D< UAM::Action, bool(*)(const Person* ) > personActionAvailability ; - static const Matrix1D< UAM::Action, bool(*)(const ContactMethod*) > cmActionAvailability ; - - static const Matrix2D< UAM::Action, SelectionState, UAM::ActionStatfulnessLevel > actionStatefulness; - - - //Helpers - bool updateAction (UAM::Action action ); - bool updateByCall (UAM::Action action, const Call* c ); - bool updateByContactMethod(UAM::Action action, const ContactMethod* cm ); - bool updateByAccount (UAM::Action action, const Account* a ); - bool updateByPerson (UAM::Action action, const Person* p ); - void updateCheckMask (int& ret, UAM::Action action, const Call* c ); - - //Attributes - Call* m_pCall ; - UserActionModelMode m_Mode ; - SelectionState m_SelectionState ; - TypedStateMachine< bool, UAM::Action> m_CurrentActions ; - Matrix1D< UAM::Action, Qt::CheckState> m_CurrentActionsState; - Matrix1D< UAM::Action, QString> m_ActionNames ; - ActiveUserActionModel* m_pActiveModel ; - FlagPack<UAM::Context> m_fContext ; - QItemSelectionModel* m_pSelectionModel {nullptr}; - QAbstractItemModel* m_pSourceModel {nullptr}; - -private: - UserActionModel* q_ptr; - -public Q_SLOTS: - //Single call mode - void slotStateChanged(); //TODO - - //CallModel mode - void updateActions(); -}; - - -/* - * This algorithm implement a matrix multiplication of the 4 sources of relevant states. - * The result of the multiplication indicate is the option is enabled in a given scenario. - */ - -#define UAMA UserActionModel::Action -#define CS Call::State -//Enabled actions -static EnumClassReordering<Call::State> co = { - CS::NEW , /* >----------| */ - CS::INCOMING , /* -----------|-------| */ - CS::RINGING , /* -----------|-------|-------| */ - CS::CURRENT , /* -----------|-------|-------|------| */ - CS::DIALING , /* -----------|-------|-------|------|-----| */ - CS::HOLD , /* -----------|-------|-------|------|-----|-------| */ - CS::FAILURE , /* -----------|-------|-------|------|-----|-------|------| */ - CS::BUSY , /* -----------|-------|-------|------|-----|-------|------|------| */ - CS::TRANSFERRED , /* -----------|-------|-------|------|-----|-------|------|------|-----| */ - CS::TRANSF_HOLD , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------| */ - CS::OVER , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------| */ - CS::ERROR , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------|-----| */ - CS::CONFERENCE , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------|-----|------| */ - CS::CONFERENCE_HOLD, /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------|-----|------|------| */ - CS::INITIALIZATION , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------|-----|------|------|-------| */ - CS::ABORTED , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------|-----|------|------|-------|------| */ - CS::CONNECTED , /* -----------|-------|-------|------|-----|-------|------|------|-----|-------|------|-----|------|------|-------|------|-----| */ -}; /* | | | | | | | | | | | | | | | | | */ - /* \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ \/ */ -const Matrix2D< UAM::Action, Call::State, bool > UserActionModelPrivate::availableActionMap = { - { UAMA::ACCEPT , {{co, { false, true , false, false, true , false, false, false, false, false, false, false, false, false, false, false, false }}}}, - { UAMA::HOLD , {{co, { false, false , false, true , false, true , false, false, false, false, false, false, true , false, false, false, false }}}}, - { UAMA::MUTE_AUDIO , {{co, { false, false , true , true , false, false, false, false, false, false, false, false, false, false, false, false, false }}}}, - { UAMA::MUTE_VIDEO , {{co, { false, false , true , true , false, false, false, false, false, false, false, false, false, false, false, false, false }}}}, - { UAMA::SERVER_TRANSFER , {{co, { false, false , false, true , false, true , false, false, false, false, false, false, false, false, false, false, false }}}}, - { UAMA::RECORD , {{co, { false, false , true , true , false, true , false, false, true , true , false, false, true , true , false, false, false }}}}, - { UAMA::HANGUP , {{co, { true , true , true , true , true , true , true , true , true , true , false, true , true , true , true , false, true }}}}, - { UAMA::JOIN , {{co, { false, false , true , true , false, true , false, false, true , true , false, false, true , true , false, false, false }}}}, - { UAMA::ADD_NEW , {{co, { false, false , false, false, false, false, false, false, false, false, false, false, false, false, false, false, false }}}}, - { UAMA::TOGGLE_VIDEO , {{co, { false, false , false, true , false, true , false, false, false, false, false, false, true , false, false, false, false }}}}, - { UAMA::ADD_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::ADD_TO_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::DELETE_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::EMAIL_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::COPY_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::BOOKMARK , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::VIEW_CHAT_HISTORY , {{co, { false, true , true , true , true , true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::ADD_CONTACT_METHOD, {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::CALL_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::EDIT_CONTACT , {{co, { false, true , true , true , false, true , true , true , true , true , true , true , false, false, true , true , true }}}}, - { UAMA::REMOVE_HISTORY , {{co, { false, false , false, false, false, false, true , true , false, false, true , false, false, false, false, false, false }}}}, -}; -#undef CS - -/** - * Assuming a call is in progress, the communication can still be valid if the account is down, however, - * this will impact the available actions - */ -const Matrix2D< UAMA, Account::RegistrationState, bool > UserActionModelPrivate::availableAccountActionMap = { - /* READY UNREGISTERED INITIALIZING TRYING ERROR */ - { UAMA::ACCEPT , {{ true , false, false, false, false }}}, - { UAMA::HOLD , {{ true , false, false, false, false }}}, - { UAMA::MUTE_AUDIO , {{ true , true , false, true , true }}}, - { UAMA::MUTE_VIDEO , {{ true , true , false, true , true }}}, - { UAMA::SERVER_TRANSFER , {{ true , false, false, false, false }}}, - { UAMA::RECORD , {{ true , true , false, true, true }}}, - { UAMA::HANGUP , {{ true , true , false, true, true }}}, - - { UAMA::JOIN , {{ true , true , false, true , true }}}, - - { UAMA::ADD_NEW , {{ true , false, false, true , true }}}, - { UAMA::TOGGLE_VIDEO , {{ true , true , false, true , true }}}, - { UAMA::ADD_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::ADD_TO_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::DELETE_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::EMAIL_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::COPY_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::BOOKMARK , {{ true , true , false, true , true }}}, - { UAMA::VIEW_CHAT_HISTORY , {{ true , true , false, true , true }}}, - { UAMA::ADD_CONTACT_METHOD, {{ true , true , false, true , true }}}, - { UAMA::CALL_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::EDIT_CONTACT , {{ true , true , false, true , true }}}, - { UAMA::REMOVE_HISTORY , {{ true , true , false, true , true }}}, -}; - -/** - * This matrix define if an option is available depending on the number of selection elements - */ -const Matrix2D< UAMA, UserActionModelPrivate::SelectionState, bool > UserActionModelPrivate::multi_call_options = { - /* NONE UNIQUE MULTI */ - { UAMA::ACCEPT , {{ false, true , true }}}, - { UAMA::HOLD , {{ false, true , false }}}, - { UAMA::MUTE_AUDIO , {{ false, true , true }}}, - { UAMA::MUTE_VIDEO , {{ false, true , true }}}, - { UAMA::SERVER_TRANSFER , {{ false, true , true }}}, - { UAMA::RECORD , {{ false, true , true }}}, - { UAMA::HANGUP , {{ false, true , true }}}, - - { UAMA::JOIN , {{ false, false, true }}}, - - { UAMA::ADD_NEW , {{ true , false, false }}}, - { UAMA::TOGGLE_VIDEO , {{ false, true , false }}}, - { UAMA::ADD_CONTACT , {{ false, true , false }}}, - { UAMA::ADD_TO_CONTACT , {{ false, true , false }}}, - { UAMA::DELETE_CONTACT , {{ false, true , false }}}, - { UAMA::EMAIL_CONTACT , {{ false, true , false }}}, - { UAMA::COPY_CONTACT , {{ false, true , false }}}, - { UAMA::BOOKMARK , {{ false, true , false }}}, - { UAMA::VIEW_CHAT_HISTORY , {{ false, true , false }}}, - { UAMA::ADD_CONTACT_METHOD, {{ false, true , false }}}, - { UAMA::CALL_CONTACT , {{ false, true , false }}}, - { UAMA::EDIT_CONTACT , {{ false, true , false }}}, - { UAMA::REMOVE_HISTORY , {{ false, true , true }}}, -}; - -/** - * This matrix define if an option is available when multiple elements with mismatching CheckState are selected - */ -const Matrix1D< UAMA, bool > UserActionModelPrivate::heterogenous_call_options = { - { UAMA::ACCEPT , true }, /* N/A */ - { UAMA::HOLD , false }, /* Do not allow to set a state */ - { UAMA::MUTE_AUDIO , true }, /* Force mute on all calls */ - { UAMA::MUTE_VIDEO , true }, /* Mute all calls */ - { UAMA::SERVER_TRANSFER , false }, /* It make no sense to let the user set this */ - { UAMA::RECORD , true }, /* Force "record" on all calls */ - { UAMA::HANGUP , true }, /* N/A */ - - { UAMA::JOIN , true }, /* N/A */ - - { UAMA::ADD_NEW , false }, /* N/A */ - { UAMA::TOGGLE_VIDEO , false }, - { UAMA::ADD_CONTACT , false }, - { UAMA::ADD_TO_CONTACT , false }, - { UAMA::DELETE_CONTACT , false }, - { UAMA::EMAIL_CONTACT , false }, - { UAMA::COPY_CONTACT , false }, - { UAMA::BOOKMARK , false }, - { UAMA::VIEW_CHAT_HISTORY , false }, - { UAMA::ADD_CONTACT_METHOD, false }, - { UAMA::CALL_CONTACT , false }, - { UAMA::EDIT_CONTACT , false }, - { UAMA::REMOVE_HISTORY , false }, -}; - -/** - * This matrix allow to enable/disable actions depending on the call protocol - */ -const Matrix2D< UAMA, Account::Protocol, bool > UserActionModelPrivate::availableProtocolActions = { - /* SIP DHT */ - { UAMA::ACCEPT , {{ true , true }}}, - { UAMA::HOLD , {{ true , true }}}, - { UAMA::MUTE_AUDIO , {{ true , true }}}, - { UAMA::MUTE_VIDEO , {{ true , true }}}, - { UAMA::SERVER_TRANSFER , {{ true , false }}}, - { UAMA::RECORD , {{ true , true }}}, - { UAMA::HANGUP , {{ true , true }}}, - - { UAMA::JOIN , {{ true , true }}}, - - { UAMA::ADD_NEW , {{ true , true }}}, - - { UAMA::TOGGLE_VIDEO , {{ true, true }}}, - { UAMA::ADD_CONTACT , {{ true, true }}}, - { UAMA::ADD_TO_CONTACT , {{ true, true }}}, - { UAMA::DELETE_CONTACT , {{ true, true }}}, - { UAMA::EMAIL_CONTACT , {{ true, true }}}, - { UAMA::COPY_CONTACT , {{ true, true }}}, - { UAMA::BOOKMARK , {{ true, true }}}, - { UAMA::VIEW_CHAT_HISTORY , {{ true, true }}}, - { UAMA::ADD_CONTACT_METHOD, {{ true, true }}}, - { UAMA::CALL_CONTACT , {{ true, true }}}, - { UAMA::EDIT_CONTACT , {{ true, true }}}, - { UAMA::REMOVE_HISTORY , {{ true, true }}}, -}; - -/** - * This matrix define if an action is stateless or stateful. The only state - * supported is "checked", but when multiple items are selected, this can - * cause a heterogeneous bunch of checked and unchecked elements, this is - * called "TRISTATE". - */ -#define ST UserActionModel::ActionStatfulnessLevel:: -const Matrix2D< UAMA, UserActionModelPrivate::SelectionState, UserActionModel::ActionStatfulnessLevel > UserActionModelPrivate::actionStatefulness = { - /* NONE UNIQUE MULTI */ - { UAMA::ACCEPT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::HOLD , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::MUTE_AUDIO , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::MUTE_VIDEO , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::SERVER_TRANSFER , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::RECORD , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::HANGUP , {{ ST UNISTATE, ST UNISTATE , ST TRISTATE }}}, - - { UAMA::JOIN , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - - { UAMA::ADD_NEW , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::TOGGLE_VIDEO , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::ADD_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::ADD_TO_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::DELETE_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::EMAIL_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::COPY_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::BOOKMARK , {{ ST UNISTATE, ST CHECKABLE , ST TRISTATE }}}, - { UAMA::VIEW_CHAT_HISTORY , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::ADD_CONTACT_METHOD, {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::CALL_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::EDIT_CONTACT , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, - { UAMA::REMOVE_HISTORY , {{ ST UNISTATE, ST UNISTATE , ST UNISTATE }}}, -}; -#undef ST - -/** - * This matrix categorize each actions. Action can be enabled in a given context - * while being hidden in another. This allow, for example, to use the - * UserActionModel to fill context menu. - */ -const Matrix1D< UAMA, FlagPack<UAM::Context>> UserActionModelPrivate::actionContext = { - { UAMA::ACCEPT , UAM::Context::MINIMAL | - UAM::Context::RECOMMENDED }, - - { UAMA::HOLD , UAM::Context::MINIMAL | - UAM::Context::RECOMMENDED }, - - { UAMA::MUTE_AUDIO , UAM::Context::RECOMMENDED }, - - { UAMA::MUTE_VIDEO , UAM::Context::RECOMMENDED }, - - { UAMA::SERVER_TRANSFER , UAM::Context::MINIMAL | - UAM::Context::RECOMMENDED }, - - { UAMA::RECORD , UAM::Context::RECOMMENDED }, - - { UAMA::HANGUP , UAM::Context::MINIMAL | - UAM::Context::RECOMMENDED }, - - { UAMA::JOIN , UAM::Context::MINIMAL | - UAM::Context::RECOMMENDED }, - - { UAMA::ADD_NEW , UAM::Context::MINIMAL | - UAM::Context::RECOMMENDED }, - - { UAMA::TOGGLE_VIDEO , UAM::Context::ADVANCED }, - { UAMA::ADD_CONTACT , UAM::Context::MANAGEMENT }, - { UAMA::ADD_TO_CONTACT , UAM::Context::MANAGEMENT }, - { UAMA::DELETE_CONTACT , UAM::Context::MANAGEMENT }, - { UAMA::EMAIL_CONTACT , UAM::Context::CONTACT }, - { UAMA::COPY_CONTACT , UAM::Context::MANAGEMENT }, - { UAMA::BOOKMARK , UAM::Context::MANAGEMENT }, - { UAMA::VIEW_CHAT_HISTORY , UAM::Context::RECOMMENDED }, - { UAMA::ADD_CONTACT_METHOD, UAM::Context::MANAGEMENT }, - { UAMA::CALL_CONTACT , UAM::Context::CONTACT }, - { UAMA::EDIT_CONTACT , UAM::Context::CONTACT }, - { UAMA::REMOVE_HISTORY , UAM::Context::MANAGEMENT }, -}; - -const Matrix1D< UAMA, FlagPack<UAM::Asset>> UserActionModelPrivate::availableByAsset = { - { UAMA::ACCEPT , UAM::Asset::CALL }, - { UAMA::HOLD , UAM::Asset::CALL }, - { UAMA::MUTE_AUDIO , UAM::Asset::CALL }, - { UAMA::MUTE_VIDEO , UAM::Asset::CALL }, - { UAMA::SERVER_TRANSFER , UAM::Asset::CALL }, - { UAMA::RECORD , UAM::Asset::CALL }, - { UAMA::HANGUP , UAM::Asset::CALL }, - { UAMA::JOIN , UAM::Asset::CALL }, - { UAMA::ADD_NEW , UAM::Asset::CALL }, - { UAMA::TOGGLE_VIDEO , UAM::Asset::CALL }, - { UAMA::ADD_CONTACT , UAM::Asset::PERSON }, - { UAMA::ADD_TO_CONTACT , UAM::Asset::CONTACT_METHOD }, - { UAMA::DELETE_CONTACT , UAM::Asset::PERSON }, - { UAMA::EMAIL_CONTACT , UAM::Asset::PERSON }, - { UAMA::COPY_CONTACT , UAM::Asset::PERSON }, - { UAMA::BOOKMARK , UAM::Asset::CONTACT_METHOD }, - { UAMA::VIEW_CHAT_HISTORY , UAM::Asset::CONTACT_METHOD }, - { UAMA::ADD_CONTACT_METHOD, UAM::Asset::PERSON }, - { UAMA::CALL_CONTACT , UAM::Asset::PERSON }, - { UAMA::EDIT_CONTACT , UAM::Asset::PERSON }, - { UAMA::REMOVE_HISTORY , UAM::Asset::CALL }, -}; - -/** - * Different objects type have access to a different subset of actions - */ -const Matrix2D< UAMA, Ring::ObjectType , bool > UserActionModelPrivate::availableObjectActions = { - /* Person ContactMethod Call Media Certificate ContactRequest*/ - { UAMA::ACCEPT , {{ false, false, true , false, false, false }}}, - { UAMA::HOLD , {{ false, false, true , true , false, false }}}, - { UAMA::MUTE_AUDIO , {{ false, false, true , true , false, false }}}, - { UAMA::MUTE_VIDEO , {{ false, false, true , true , false, false }}}, - { UAMA::SERVER_TRANSFER , {{ false, false, true , false, false, false }}}, - { UAMA::RECORD , {{ false, false, true , true , false, false }}}, - { UAMA::HANGUP , {{ false, false, true , false, false, false }}}, - { UAMA::JOIN , {{ false, false, true , false, false, false }}}, - { UAMA::ADD_NEW , {{ false, false, true , false, false, false }}}, - { UAMA::TOGGLE_VIDEO , {{ false, false, true , true , false, false }}}, - { UAMA::ADD_CONTACT , {{ false, true , true , false, true , false }}}, - { UAMA::ADD_TO_CONTACT , {{ false, true , true , false, true , false }}}, - { UAMA::DELETE_CONTACT , {{ true , true , true , false, true , false }}}, - { UAMA::EMAIL_CONTACT , {{ true , true , true , false, true , false }}}, - { UAMA::COPY_CONTACT , {{ true , true , true , false, true , false }}}, - { UAMA::BOOKMARK , {{ true , true , true , false, true , false }}}, - { UAMA::VIEW_CHAT_HISTORY , {{ true , true , true , true , true , true }}}, - { UAMA::ADD_CONTACT_METHOD, {{ true , true , true , false, true , false }}}, - { UAMA::CALL_CONTACT , {{ true , true , true , false, true , false }}}, - { UAMA::EDIT_CONTACT , {{ true , true , true , false, true , false }}}, - { UAMA::REMOVE_HISTORY , {{ true , true , true , false, true , false }}}, -}; - -#define P_CB [](const Person* p) -> bool - -/** - * Persons aren't stateful but rather have a series of properties. Therefore a - * series of state machines cannot properly represent that state of every - * actions. - */ -const Matrix1D< UAM::Action, bool(*)(const Person*)> UserActionModelPrivate::personActionAvailability = { - { UAMA::ACCEPT , nullptr }, - { UAMA::HOLD , nullptr }, - { UAMA::MUTE_AUDIO , nullptr }, - { UAMA::MUTE_VIDEO , nullptr }, - { UAMA::SERVER_TRANSFER , nullptr }, - { UAMA::RECORD , nullptr }, - { UAMA::HANGUP , nullptr }, - { UAMA::JOIN , nullptr }, - { UAMA::ADD_NEW , nullptr }, - { UAMA::TOGGLE_VIDEO , nullptr }, - { UAMA::ADD_CONTACT , nullptr }, - { UAMA::ADD_TO_CONTACT , nullptr }, - { UAMA::DELETE_CONTACT , P_CB { return p->collection() && - p->collection()->supportedFeatures() & - CollectionInterface::SupportedFeatures::REMOVE; - }}, - { UAMA::EMAIL_CONTACT , P_CB { return ! p->preferredEmail().isEmpty(); }}, - { UAMA::COPY_CONTACT , nullptr }, - { UAMA::BOOKMARK , nullptr }, - { UAMA::VIEW_CHAT_HISTORY , P_CB { - return p->hasRecording( - media::Media::Type::TEXT, - media::Media::Direction::OUT - ); - }}, - { UAMA::ADD_CONTACT_METHOD, nullptr }, - { UAMA::CALL_CONTACT , P_CB { return p->isReachable(); }}, - { UAMA::EDIT_CONTACT , P_CB { return p->collection() && - p->collection()->supportedFeatures() & - CollectionInterface::SupportedFeatures::EDIT; - }}, - { UAMA::REMOVE_HISTORY , P_CB { return p->hasBeenCalled(); }}, -}; -#undef P_C - -#define CM_CB [](const ContactMethod* cm) -> bool - -/** - * ContactMethods aren't stateful but rather have a series of properties. - * Therefore a series of state machines cannot properly represent that state of - * every actions. - */ -const Matrix1D< UAM::Action, bool(*)(const ContactMethod*)> UserActionModelPrivate::cmActionAvailability = { - { UAMA::ACCEPT , nullptr }, - { UAMA::HOLD , nullptr }, - { UAMA::MUTE_AUDIO , nullptr }, - { UAMA::MUTE_VIDEO , nullptr }, - { UAMA::SERVER_TRANSFER , nullptr }, - { UAMA::RECORD , nullptr }, - { UAMA::HANGUP , nullptr }, - { UAMA::JOIN , nullptr }, - { UAMA::ADD_NEW , nullptr }, - { UAMA::TOGGLE_VIDEO , nullptr }, - { UAMA::ADD_CONTACT , CM_CB { return (!cm) || (!cm->contact()) - || cm->contact()->isPlaceHolder(); - }}, - { UAMA::ADD_TO_CONTACT , CM_CB { return (!cm) || !cm->contact(); }}, - { UAMA::DELETE_CONTACT , CM_CB { return cm && cm->contact() && - cm->contact()->collection() && - cm->contact()->collection()->supportedFeatures() & - CollectionInterface::SupportedFeatures::REMOVE; - }}, - { UAMA::EMAIL_CONTACT , CM_CB { return cm && cm->contact() && - !cm->contact()->preferredEmail().isEmpty(); - }}, - { UAMA::COPY_CONTACT , CM_CB { return cm && cm->contact(); }}, - { UAMA::BOOKMARK , nullptr }, - { UAMA::VIEW_CHAT_HISTORY , CM_CB { - return cm && (( - cm->textRecording() - && !cm->textRecording()->isEmpty() - ) || ( - cm->protocolHint() == URI::ProtocolHint::RING_USERNAME || - cm->protocolHint() == URI::ProtocolHint::RING - )); - }}, - { UAMA::ADD_CONTACT_METHOD, CM_CB { return cm && cm->contact(); }}, - { UAMA::CALL_CONTACT , CM_CB { return (!cm) || cm->isReachable(); }}, - { UAMA::EDIT_CONTACT , CM_CB { return cm && cm->contact(); }}, - { UAMA::REMOVE_HISTORY , CM_CB { return cm && cm->callCount(); }}, -}; -#undef CM_CB - -UserActionModelPrivate::UserActionModelPrivate(UserActionModel* parent, const FlagPack<UAM::Context>& c) : QObject(parent),q_ptr(parent), -m_pCall(nullptr), m_pActiveModel(nullptr), m_fContext(c) -{ - //Init the default names - m_ActionNames = { - { UAMA::ACCEPT , QObject::tr("Accept" )}, - { UAMA::HOLD , QObject::tr("Hold" )}, - { UAMA::MUTE_AUDIO , QObject::tr("Mute audio" )}, - { UAMA::MUTE_VIDEO , QObject::tr("Mute video" )}, - { UAMA::SERVER_TRANSFER , QObject::tr("Server transfer" )}, - { UAMA::RECORD , QObject::tr("Record" )}, - { UAMA::HANGUP , QObject::tr("Hangup" )}, - { UAMA::JOIN , QObject::tr("Join" )}, - { UAMA::ADD_NEW , QObject::tr("Add new" )}, - { UAMA::TOGGLE_VIDEO , QObject::tr("Toggle video" )}, - { UAMA::ADD_CONTACT , QObject::tr("Add a contact" )}, - { UAMA::ADD_TO_CONTACT , QObject::tr("Add to existing contact")}, - { UAMA::DELETE_CONTACT , QObject::tr("Delete contact" )}, - { UAMA::EMAIL_CONTACT , QObject::tr("Email contact" )}, - { UAMA::COPY_CONTACT , QObject::tr("Copy contact" )}, - { UAMA::BOOKMARK , QObject::tr("Bookmark" )}, - { UAMA::VIEW_CHAT_HISTORY , QObject::tr("Open chat" )}, - { UAMA::ADD_CONTACT_METHOD, QObject::tr("Add phone number" )}, - { UAMA::CALL_CONTACT , QObject::tr("Call again" )}, - { UAMA::EDIT_CONTACT , QObject::tr("Edit contact details" )}, - { UAMA::REMOVE_HISTORY , QObject::tr("Remove from history" )}, - }; - - m_CurrentActionsState = { - { UAMA::ACCEPT , Qt::Unchecked}, - { UAMA::HOLD , Qt::Unchecked}, - { UAMA::MUTE_AUDIO , Qt::Unchecked}, - { UAMA::MUTE_VIDEO , Qt::Unchecked}, - { UAMA::SERVER_TRANSFER , Qt::Unchecked}, - { UAMA::RECORD , Qt::Unchecked}, - { UAMA::HANGUP , Qt::Unchecked}, - { UAMA::JOIN , Qt::Unchecked}, - { UAMA::ADD_NEW , Qt::Unchecked}, - { UAMA::TOGGLE_VIDEO , Qt::Unchecked}, - { UAMA::ADD_CONTACT , Qt::Unchecked}, - { UAMA::ADD_TO_CONTACT , Qt::Unchecked}, - { UAMA::DELETE_CONTACT , Qt::Unchecked}, - { UAMA::EMAIL_CONTACT , Qt::Unchecked}, - { UAMA::COPY_CONTACT , Qt::Unchecked}, - { UAMA::BOOKMARK , Qt::Unchecked}, - { UAMA::VIEW_CHAT_HISTORY , Qt::Unchecked}, - { UAMA::ADD_CONTACT_METHOD, Qt::Unchecked}, - { UAMA::CALL_CONTACT , Qt::Unchecked}, - { UAMA::EDIT_CONTACT , Qt::Unchecked}, - { UAMA::REMOVE_HISTORY , Qt::Unchecked}, - }; -} - -#undef UAMA -#undef UAM - -/** - * Create an UserActionModel around a single call. This won't take advantage - * of the multiselection feature. - */ -UserActionModel::UserActionModel(Call* parent, const FlagPack<UserActionModel::Context> c) : QAbstractListModel(parent),d_ptr(new UserActionModelPrivate(this,c)) -{ - Q_ASSERT(parent != nullptr); - Q_ASSERT(parent->state() != Call::State::OVER); - d_ptr->m_SelectionState = UserActionModelPrivate::SelectionState::UNIQUE; - d_ptr->m_Mode = UserActionModelPrivate::UserActionModelMode::CALL; - d_ptr->m_pCall = parent; - - connect(&AccountModel::instance(), SIGNAL(accountStateChanged(Account*,Account::RegistrationState)), d_ptr.data(), SLOT(slotStateChanged())); - d_ptr->updateActions(); -} - -/** - * Create an UserActionModel around the CallModel selected call(s) - */ -UserActionModel::UserActionModel(QAbstractItemModel* parent, const FlagPack<UserActionModel::Context> c) : QAbstractListModel(parent),d_ptr(new UserActionModelPrivate(this,c)) -{ - Q_ASSERT(parent != nullptr); - d_ptr->m_Mode = UserActionModelPrivate::UserActionModelMode::GENERIC; - d_ptr->m_SelectionState = UserActionModelPrivate::SelectionState::UNIQUE; - d_ptr->m_pSourceModel = parent; - - connect(&AccountModel::instance(), &AccountModel::accountStateChanged , d_ptr.data(), &UserActionModelPrivate::updateActions); - - if (auto callmodel = qobject_cast<CallModel*>(parent)) { - setSelectionModel(callmodel->selectionModel()); - connect(callmodel, &CallModel::callStateChanged , d_ptr.data(), &UserActionModelPrivate::updateActions); - connect(callmodel, &CallModel::mediaStateChanged, d_ptr.data(), &UserActionModelPrivate::updateActions); - connect(callmodel, &CallModel::dialNumberChanged, d_ptr.data(), &UserActionModelPrivate::updateActions); - } - //TODO add other relevant models here Categorized*, RecentModel, etc - - d_ptr->updateActions(); -} - -UserActionModel::~UserActionModel() -{ - -} - -QHash<int,QByteArray> UserActionModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - roles[(int)Role::ACTION] = "action"; - } - return roles; -} - -QVariant UserActionModel::data(const QModelIndex& idx, int role ) const -{ - if ((!idx.isValid()) || !(idx.row()>=0 && idx.row() < enum_class_size<UserActionModel::Action>())) - return QVariant(); - - UserActionModel::Action action = static_cast<UserActionModel::Action>(idx.row()); - - switch(role) { - case Qt::DisplayRole: - return d_ptr->m_ActionNames[action]; - case Qt::CheckStateRole: - if (d_ptr->actionStatefulness[action][d_ptr->m_SelectionState] != UserActionModel::ActionStatfulnessLevel::UNISTATE) - return d_ptr->m_CurrentActionsState[action]; - break; - case Qt::DecorationRole: { - UserActionElement state; - state.action = action ; - state.calls = {} ; - state.checkState = Qt::Unchecked; - return GlobalInstances::pixmapManipulator().userActionIcon(state); - } - case UserActionModel::Role::ACTION: - return QVariant::fromValue(static_cast<Action>(idx.row())); - }; - - return QVariant(); -} - -int UserActionModel::rowCount(const QModelIndex& parent ) const -{ - return parent.isValid() ? 0 : static_cast<int>(Action::COUNT__); -} - -///For now, this model probably won't be used that way -Qt::ItemFlags UserActionModel::flags(const QModelIndex& idx ) const -{ - if ((!idx.isValid()) || !(idx.row()>=0 && idx.row() < enum_class_size<UserActionModel::Action>())) - return Qt::NoItemFlags; - - UserActionModel::Action action = static_cast<UserActionModel::Action>(idx.row()); - - return (d_ptr->m_CurrentActions[action] ? (Qt::ItemIsEnabled | Qt::ItemIsSelectable) : Qt::NoItemFlags) - | (d_ptr->actionStatefulness[action][d_ptr->m_SelectionState] != UserActionModel::ActionStatfulnessLevel::UNISTATE - ? Qt::ItemIsUserCheckable : Qt::NoItemFlags); -} - -// ///This model is read only -bool UserActionModel::setData(const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED( index ) - Q_UNUSED( value ) - Q_UNUSED( role ) - return false; -} - -bool UserActionModel::isActionEnabled( UserActionModel::Action action ) const -{ - if (!d_ptr->m_pCall) - return false; - - return d_ptr->availableActionMap[action][d_ptr->m_pCall->state()]; -} - -void UserActionModelPrivate::slotStateChanged() -{ - emit q_ptr->actionStateChanged(); -} - -void UserActionModelPrivate::updateCheckMask(int& ret, UserActionModel::Action action, const Call* c) -{ - //TODO c will be nullptr if the selection is a person or a contact method - //there is still a need to update the check mask, but it is less relevant - //so it can wait for later. This will cause some weird issues with the - //recent model - if (!c) - return; - - switch(action) { - case UserActionModel::Action::ACCEPT : - ret += 0; - break; - case UserActionModel::Action::HOLD : - ret += c->state() == Call::State::HOLD? 100 : 1; - break; - case UserActionModel::Action::MUTE_AUDIO : { - auto a = c->firstMedia<media::Audio>(media::Media::Direction::OUT); - ret += a && a->state() == media::Media::State::MUTED ? 100 : 1; - } - break; - case UserActionModel::Action::MUTE_VIDEO : { - auto v = c->firstMedia<media::Video>(media::Media::Direction::OUT); - ret += v && v->state() == media::Media::State::MUTED ? 100 : 1; - } - break; - case UserActionModel::Action::SERVER_TRANSFER : - ret += c->state() == Call::State::TRANSFERRED? 100 : 1; - break; - case UserActionModel::Action::RECORD : - ret += c->isRecording(media::Media::Type::AUDIO,media::Media::Direction::OUT) ? 100 : 1; - break; - case UserActionModel::Action::HANGUP : - ret += 0; - break; - case UserActionModel::Action::JOIN : - ret += 0; - break; - case UserActionModel::Action::ADD_NEW : - ret += 0; - break; - case UserActionModel::Action::TOGGLE_VIDEO : - case UserActionModel::Action::ADD_CONTACT : - case UserActionModel::Action::ADD_TO_CONTACT : - case UserActionModel::Action::DELETE_CONTACT : - case UserActionModel::Action::EMAIL_CONTACT : - case UserActionModel::Action::COPY_CONTACT : - case UserActionModel::Action::BOOKMARK : - case UserActionModel::Action::VIEW_CHAT_HISTORY : - case UserActionModel::Action::ADD_CONTACT_METHOD: - case UserActionModel::Action::CALL_CONTACT : - case UserActionModel::Action::EDIT_CONTACT : - case UserActionModel::Action::REMOVE_HISTORY : - case UserActionModel::Action::COUNT__: - break; - }; - - //Avoid the noise - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wswitch-enum" - //Update the labels - switch (action) { - case UserActionModel::Action::ACCEPT : - switch(c->state()) { - case Call::State::DIALING : - m_ActionNames.setAt(UserActionModel::Action::ACCEPT, QObject::tr("Call")); - break; - default: - m_ActionNames.setAt(UserActionModel::Action::ACCEPT, QObject::tr("Accept")); - break; - } - break; - case UserActionModel::Action::HOLD : - switch(c->state()) { - case Call::State::HOLD : - case Call::State::CONFERENCE_HOLD: - case Call::State::TRANSF_HOLD : - m_ActionNames.setAt(UserActionModel::Action::HOLD, QObject::tr("Unhold")); - break; - default: - m_ActionNames.setAt(UserActionModel::Action::HOLD, QObject::tr("Hold")); - break; - } - break; - case UserActionModel::Action::HANGUP : - switch(c->state()) { - case Call::State::DIALING : - case Call::State::NEW : - m_ActionNames.setAt(UserActionModel::Action::HANGUP, QObject::tr("Cancel")); - break; - case Call::State::FAILURE : - case Call::State::ERROR : - case Call::State::COUNT__ : - case Call::State::INITIALIZATION : - case Call::State::BUSY : - m_ActionNames.setAt(UserActionModel::Action::HANGUP, QObject::tr("Remove")); - break; - default: - m_ActionNames.setAt(UserActionModel::Action::HANGUP, QObject::tr("Hangup")); - break; - } - break; - case UserActionModel::Action::JOIN : - case UserActionModel::Action::ADD_NEW : - case UserActionModel::Action::COUNT__ : - case UserActionModel::Action::MUTE_AUDIO : - case UserActionModel::Action::MUTE_VIDEO : - case UserActionModel::Action::SERVER_TRANSFER : - case UserActionModel::Action::RECORD : - case UserActionModel::Action::TOGGLE_VIDEO : - case UserActionModel::Action::ADD_CONTACT : - case UserActionModel::Action::ADD_TO_CONTACT : - case UserActionModel::Action::DELETE_CONTACT : - case UserActionModel::Action::EMAIL_CONTACT : - case UserActionModel::Action::COPY_CONTACT : - case UserActionModel::Action::BOOKMARK : - case UserActionModel::Action::VIEW_CHAT_HISTORY : - case UserActionModel::Action::ADD_CONTACT_METHOD: - case UserActionModel::Action::CALL_CONTACT : - case UserActionModel::Action::EDIT_CONTACT : - case UserActionModel::Action::REMOVE_HISTORY : - break; - } - #pragma GCC diagnostic pop -} - -bool UserActionModelPrivate::updateByCall(UserActionModel::Action action, const Call* c) -{ - if (!c) - return false; - Account* a = c->account() ? c->account() : AvailableAccountModel::instance().currentDefaultAccount(); - - return ( - availableActionMap [action] [c->state() ] && - multi_call_options [action] [m_SelectionState ] && - actionContext [action] & m_fContext && - updateByAccount(action, a) - ); -} - -bool UserActionModelPrivate::updateByAccount(UserActionModel::Action action, const Account* a) -{ - if (!a) - return false; - return ( - availableAccountActionMap [action] [a->registrationState() ] && - availableProtocolActions [action] [a->protocol() ] // - ); -} - -bool UserActionModelPrivate::updateByContactMethod(UserActionModel::Action action, const ContactMethod* cm) -{ - // Some actions have a conditional CM - if (!cm) - return cmActionAvailability[action] ? - cmActionAvailability[action](nullptr) : true; - - Account* a = cm->account() ? cm->account() : AvailableAccountModel::instance().currentDefaultAccount(); - - return updateByAccount(action, a) && ( - (!cmActionAvailability[action]) || cmActionAvailability[action](cm) - ); -} - -bool UserActionModelPrivate::updateByPerson(UserActionModel::Action action, const Person* p) -{ - return (!personActionAvailability[action]) || personActionAvailability[action](p); -} - -bool UserActionModelPrivate::updateAction(UserActionModel::Action action) -{ - int state = 0; - switch(m_Mode) { - case UserActionModelMode::CALL: - updateCheckMask(state,action,m_pCall); - m_CurrentActionsState.setAt(action, state / 100 ? Qt::Checked : Qt::Unchecked); - - return updateByCall(action, m_pCall); - case UserActionModelMode::GENERIC: { - bool ret = true; - - m_SelectionState = m_pSelectionModel ? ( - m_pSelectionModel->selectedRows().size() > 1 ? - SelectionState::MULTI : - SelectionState::UNIQUE - ) : SelectionState::NONE ; - - //Aggregate and reduce the action state for each selected calls - if (m_pSelectionModel && (m_pSelectionModel->selectedRows().size() || m_pSelectionModel->currentIndex().isValid())) { - - auto selected = m_pSelectionModel->selectedRows(); - - if (selected.isEmpty() && m_pSelectionModel->currentIndex().isValid()) - selected << m_pSelectionModel->currentIndex(); - - foreach (const QModelIndex& idx, selected) { - - const QVariant objTv = idx.data(static_cast<int>(Ring::Role::ObjectType)); - - //Be sure the model support the UAM abstraction - if (!objTv.canConvert<Ring::ObjectType>()) { - qWarning() << "Cannot determine object type"; - continue; - } - - const auto objT = qvariant_cast<Ring::ObjectType>(objTv); - - ret &= availableObjectActions[action][objT]; - - //There is no point in doing further checks - if (!ret) { - continue; - } - - switch(objT) { - case Ring::ObjectType::Person : { - - const auto p = qvariant_cast<Person*>(idx.data(static_cast<int>(Ring::Role::Object))); - - ret &= updateByPerson( action, p ); - - break; - } - case Ring::ObjectType::ContactMethod : { - - const auto cm = qvariant_cast<ContactMethod*>(idx.data(static_cast<int>(Ring::Role::Object))); - - ret &= cm ? updateByContactMethod( action, cm ) : false; - - break; - } - case Ring::ObjectType::Call : { - - const auto c = qvariant_cast<Call*>(idx.data(static_cast<int>(Ring::Role::Object))); - - ret &= updateByCall( action, c ); - - // Dialing (search field) calls have a new URI with every - // keystroke. Check is such URI match an existing one. This - // changes the availability of some actions. For example, - // the offline chat only works for Ring CM *or* SIP CM with - // an existing chat history. - if (c->state() == Call::State::DIALING) { - ret &= updateByContactMethod( - action, PhoneDirectoryModel::instance().getExistingNumberIf( - c->peerContactMethod()->uri(), - [](const ContactMethod* cm) -> bool { return cm->account();} - ) - ); - } - - updateCheckMask( state ,action, c ); //TODO abstract this out - - break; - } - case Ring::ObjectType::Media : //TODO - case Ring::ObjectType::Certificate : //TODO - case Ring::ObjectType::ContactRequest : //TODO - case Ring::ObjectType::COUNT__ : - break; - } - } - } - else { - Account* a = AvailableAccountModel::instance().currentDefaultAccount(); - ret = multi_call_options[action][UserActionModelPrivate::SelectionState::NONE] - && (a?availableAccountActionMap[action][a->registrationState()]:false); - } - - //Detect if the multiple selection has mismatching item states, disable it if necessary - m_CurrentActionsState.setAt(action, (state % 100 && state / 100) ? Qt::PartiallyChecked : (state / 100 ? Qt::Checked : Qt::Unchecked)); - return ret && (m_CurrentActionsState[action] != Qt::PartiallyChecked || heterogenous_call_options[action]); - } - }; - return false; -} - -void UserActionModelPrivate::updateActions() -{ - for (UserActionModel::Action action : EnumIterator<UserActionModel::Action>()) - m_CurrentActions[action] = updateAction(action); - emit q_ptr->dataChanged(q_ptr->index(0,0),q_ptr->index(enum_class_size<UserActionModel::Action>()-1,0)); -} - -uint UserActionModel::relativeIndex( UserActionModel::Action action ) const -{ - int i(0),ret(0); - while (i != static_cast<int>(action) && i < enum_class_size<UserActionModel::Action>()) { - ret += isActionEnabled(static_cast<UserActionModel::Action>(i))?1:0; - i++; - } - return ret; -} - -bool UserActionModel::execute(const UserActionModel::Action action) const -{ - - // For now, only handle single selection, multi-selection could be - // re-enabled later - - // TODO This will be cleaned up later - if (! d_ptr->m_pSelectionModel->hasSelection () && action == UserActionModel::Action::ADD_NEW) { - if (UserActions::addNew()) { - d_ptr->updateActions(); - return true; - } - } - - foreach (const QModelIndex& idx, d_ptr->m_pSelectionModel->selectedRows()) { - const QVariant objTv = idx.data(static_cast<int>(Ring::Role::ObjectType)); - - //Be sure the model support the UAM abstraction - if (!objTv.canConvert<Ring::ObjectType>()) { - qWarning() << "Cannot determine object type"; - continue; - } - - const auto objT = qvariant_cast<Ring::ObjectType>(objTv); - - Call* c = nullptr; - // Account* a = nullptr; TODO: uncomment when account is needed - ContactMethod* cm = nullptr; - Person* p = nullptr; - - // Deduce each kind of objects from the relations - switch(objT) { - case Ring::ObjectType::Person : - p = qvariant_cast<Person*>(idx.data(static_cast<int>(Ring::Role::Object))); - cm = p->phoneNumbers().size() == 1 ? p->phoneNumbers()[0] : nullptr; - // a = cm ? cm->account() : nullptr; TODO: uncomment when account is needed - break; - case Ring::ObjectType::ContactMethod : - cm = qvariant_cast<ContactMethod*>(idx.data(static_cast<int>(Ring::Role::Object))); - // a = cm->account(); TODO: uncomment when account is needed - p = cm->contact(); - //TODO maybe add "QList<Call*> currentCalls()" const to ContactMethod::? - break; - case Ring::ObjectType::Call : - c = qvariant_cast<Call*>(idx.data(static_cast<int>(Ring::Role::Object))); - cm = c->peerContactMethod(); - p = cm ? cm->contact() : nullptr; - // a = c->account(); TODO: uncomment when account is needed - break; - case Ring::ObjectType::Media : //TODO - case Ring::ObjectType::Certificate : //TODO - case Ring::ObjectType::ContactRequest : //TODO - case Ring::ObjectType::COUNT__ : - break; - } - - // Perform the actions - switch(action) { - case UserActionModel::Action::ACCEPT : - if (UserActions::accept(c)) - d_ptr->updateActions(); - break; - case UserActionModel::Action::HOLD : - switch(d_ptr->m_CurrentActionsState[UserActionModel::Action::HOLD]) { - case Qt::Checked: - if (UserActions::unhold(c)) - d_ptr->updateActions(); - break; - case Qt::Unchecked: - if (UserActions::hold(c)) - d_ptr->updateActions(); - break; - case Qt::PartiallyChecked: - //Invalid - break; - }; - break; - case UserActionModel::Action::MUTE_AUDIO : - { - bool mute = d_ptr->m_CurrentActionsState[UserActionModel::Action::MUTE_AUDIO] != Qt::Checked; - UserActions::muteAudio(c, mute); - d_ptr->updateActions(); - } - break; - case UserActionModel::Action::MUTE_VIDEO : - { - bool mute = d_ptr->m_CurrentActionsState[UserActionModel::Action::MUTE_VIDEO] != Qt::Checked; - UserActions::muteVideo(c, mute); - d_ptr->updateActions(); - } - break; - case UserActionModel::Action::SERVER_TRANSFER : - UserActions::transfer(c); - break; - case UserActionModel::Action::RECORD : - if (UserActions::recordAudio(c)) //TODO handle other recording types - d_ptr->updateActions(); - break; - case UserActionModel::Action::HANGUP : - if (UserActions::hangup(c)) - d_ptr->updateActions(); - break; - case UserActionModel::Action::JOIN : - //TODO unimplemented - break; - case UserActionModel::Action::ADD_NEW : - if (UserActions::addNew()) - d_ptr->updateActions(); - break; - case UserActionModel::Action::TOGGLE_VIDEO : - break; - case UserActionModel::Action::ADD_CONTACT : - UserActions::addPerson(cm); - break; - case UserActionModel::Action::ADD_TO_CONTACT : - UserActions::addToPerson(cm); - break; - case UserActionModel::Action::DELETE_CONTACT : - UserActions::deleteContact(p); - break; - case UserActionModel::Action::EMAIL_CONTACT : - UserActions::sendEmail(p); - break; - case UserActionModel::Action::COPY_CONTACT : - GlobalInstances::actionExtender().copyInformation( - RingMimes::payload(c, cm, p) - ); - break; - case UserActionModel::Action::BOOKMARK : - UserActions::bookmark(cm); - break; - case UserActionModel::Action::VIEW_CHAT_HISTORY : - if (p) - GlobalInstances::actionExtender().viewChatHistory(p); - else - GlobalInstances::actionExtender().viewChatHistory(cm); - break; - case UserActionModel::Action::ADD_CONTACT_METHOD: - UserActions::addToPerson(p); - break; - case UserActionModel::Action::CALL_CONTACT : - UserActions::callAgain(cm); - break; - case UserActionModel::Action::EDIT_CONTACT : - UserActions::editPerson(p); - break; - case UserActionModel::Action::REMOVE_HISTORY : - UserActions::removeFromHistory(c); - break; - case UserActionModel::Action::COUNT__: - break; - }; - } - - return true; //TODO handle errors -} - -UserActionModel* UserActionModel::operator<<(UserActionModel::Action& action) -{ - execute(action); - return this; -} - - -UserActionModel* operator<<(UserActionModel* m,UserActionModel::Action action) -{ - return (!m)? nullptr : (*m) << action; -} - -/** - * Execute an action - * @param idx A model index. It can be from proxies. - */ -bool UserActionModel::execute(const QModelIndex& idx) const -{ - QModelIndex idx2 = idx; - - //Make this API a little more user friendly and unwind the proxies - QAbstractProxyModel* m = nullptr; - while (idx2.model() != this && idx2.isValid()) { - m = qobject_cast<QAbstractProxyModel*>(const_cast<QAbstractItemModel*>(idx2.model())); - if (m) - idx2 = m->mapToSource(idx2); - else - break; - } - - if (!idx2.isValid()) - return false; - - UserActionModel::Action action = static_cast<UserActionModel::Action>(idx2.row()); - return execute(action); -} - -///Get a model filter with only the available actions -QAbstractItemModel* UserActionModel::activeActionModel() const -{ - if (!d_ptr->m_pActiveModel) - d_ptr->m_pActiveModel = new ActiveUserActionModel(const_cast<UserActionModel*>(this)); - return d_ptr->m_pActiveModel; -} - -//Do not display disabled account -bool ActiveUserActionModel::filterAcceptsRow(int source_row, const QModelIndex& source_parent) const -{ - return sourceModel()->index(source_row,0,source_parent).flags() & Qt::ItemIsEnabled; -} - -///Use a custom selection model -void UserActionModel::setSelectionModel(QItemSelectionModel* sm) -{ - d_ptr->m_pSelectionModel = sm; - connect(sm, &QItemSelectionModel::currentRowChanged , d_ptr.data(), &UserActionModelPrivate::updateActions); - connect(sm, &QItemSelectionModel::selectionChanged , d_ptr.data(), &UserActionModelPrivate::updateActions); - - d_ptr->updateActions(); -} - -#include <useractionmodel.moc> diff --git a/src/vcard.h b/src/vcard.h index 3036624b06ae578972cec0087b3940c63d6f7cb2..a5b7c1114dbcb3486e574845c1d9754163868a84 100644 --- a/src/vcard.h +++ b/src/vcard.h @@ -18,10 +18,16 @@ ***************************************************************************/ #pragma once +#include <QHash> +#include <QByteArray> + namespace lrc { namespace vCard { + +constexpr static const char* PROFILE_VCF = "x-ring/ring.profile.vcard"; + struct Delimiter { constexpr static const char* SEPARATOR_TOKEN = ";"; constexpr static const char* END_LINE_TOKEN = "\n"; @@ -61,5 +67,36 @@ struct Property { constexpr static const char* X_RINGACCOUNT = "X-RINGACCOUNTID"; }; + +namespace utils { + /** + * Payload to vCard + * @param content payload + * @return the vCard representation + */ + static QHash<QByteArray, QByteArray> toHashMap(const QByteArray& content) + { + // TODO without Qt + QHash<QByteArray, QByteArray> vCard; + QByteArray previousKey,previousValue; + const QList<QByteArray> lines = content.split('\n'); + + foreach (const QByteArray& property, lines) { + //Ignore empty lines + if (property.size()) { + //Some properties are over multiple lines + if (property[0] == ' ' && previousKey.size()) { + previousValue += property.right(property.size()-1); + } + + //Do not use split, URIs can have : in them + const int dblptPos = property.indexOf(':'); + const QByteArray k(property.left(dblptPos)),v(property.right(property.size()-dblptPos-1)); + vCard[k] = v; + } + } + return vCard; + } +} } } diff --git a/src/video/channel.cpp b/src/video/channel.cpp deleted file mode 100644 index 2fe55ce7acddf3fd933dd79e010924c0b3d99404..0000000000000000000000000000000000000000 --- a/src/video/channel.cpp +++ /dev/null @@ -1,147 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "channel.h" - -//Ring -#include "resolution.h" -#include "rate.h" -#include "device.h" -#include "../dbus/videomanager.h" -#include "../private/videochannel_p.h" -#include "../private/videodevice_p.h" - -VideoChannelPrivate::VideoChannelPrivate() : m_pCurrentResolution(nullptr), -m_pDevice(nullptr) -{ -} - -Video::Channel::Channel(Video::Device* dev,const QString& name) : QAbstractListModel(dev), -d_ptr(new VideoChannelPrivate()) -{ - d_ptr->m_Name = name; - d_ptr->m_pDevice = dev; -} - -Video::Channel::~Channel() -{ -// delete d_ptr; -} - -QVariant Video::Channel::data( const QModelIndex& index, int role) const -{ - if (index.isValid() && role == Qt::DisplayRole && d_ptr->m_lValidResolutions.size() > index.row()) { - return d_ptr->m_lValidResolutions[index.row()]->name(); - } - return QVariant(); -} - -int Video::Channel::rowCount( const QModelIndex& parent) const -{ - return (parent.isValid())?0:d_ptr->m_lValidResolutions.size(); -} - -Qt::ItemFlags Video::Channel::flags( const QModelIndex& idx) const -{ - if (idx.column() == 0) - return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return QAbstractItemModel::flags(idx); -} - -bool Video::Channel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -int Video::Channel::relativeIndex() { - return d_ptr->m_pDevice->channelList().indexOf(this); -} - -bool Video::Channel::setActiveResolution(int idx) -{ - if (idx < 0 || idx >= d_ptr->m_lValidResolutions.size()) return false; - return setActiveResolution(d_ptr->m_lValidResolutions[idx]); -} - -bool Video::Channel::setActiveResolution(Video::Resolution* res) { - if ((!res) || d_ptr->m_lValidResolutions.indexOf(res) == -1 || res->name().isEmpty()) { - qWarning() << "Invalid active resolution: " << (res?res->name():"NULL"); - return false; - } - - if (d_ptr->m_pCurrentResolution == res) - return false; - - d_ptr->m_pCurrentResolution = res; - d_ptr->m_pDevice->save(); - return true; -} - -bool Video::Channel::setActiveMode(int resIndex, int rateIndex) { - if (resIndex < 0 || resIndex >= d_ptr->m_lValidResolutions.size()) return false; - auto res = d_ptr->m_lValidResolutions[resIndex]; - if (rateIndex < 0 || rateIndex >= res->validRates().size()) return false; - auto rate = res->validRates()[rateIndex]; - - if (d_ptr->m_pCurrentResolution == res && - res->activeRate() == rate) { - qWarning() << "Mode already set: " << (res ? res->name() : "NULL") << (rate ? rate->name() : "NULL"); - return false; - } - - d_ptr->m_pCurrentResolution = res; - d_ptr->m_pCurrentResolution->setActiveRate(rate); - return true; -} - -Video::Resolution* Video::Channel::activeResolution() -{ - //If it is the current device, then there is "current" resolution - if ((!d_ptr->m_pCurrentResolution) && d_ptr->m_pDevice->isActive()) { - VideoManagerInterface& interface = VideoManager::instance(); - const QString res = QMap<QString,QString>(interface.getSettings(d_ptr->m_pDevice->id()))[VideoDevicePrivate::PreferenceNames::SIZE]; - foreach(Video::Resolution* r, validResolutions()) { - if (r->name() == res) { - d_ptr->m_pCurrentResolution = r; - break; - } - } - } - //If it isn't the current _or_ the current res is invalid, pick the first valid one - if (!d_ptr->m_pCurrentResolution && validResolutions().size()) { - d_ptr->m_pCurrentResolution = validResolutions().first(); - } - - return d_ptr->m_pCurrentResolution; -} - -QString Video::Channel::name() const -{ - return d_ptr->m_Name; -} - -QList<Video::Resolution*> Video::Channel::validResolutions() const -{ - return d_ptr->m_lValidResolutions; -} -Video::Device* Video::Channel::device() const -{ - return d_ptr->m_pDevice; -} diff --git a/src/video/channel.h b/src/video/channel.h deleted file mode 100644 index 70d3b6a79fb9ae508b175b9f8fb963cde4d782b6..0000000000000000000000000000000000000000 --- a/src/video/channel.h +++ /dev/null @@ -1,65 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -//Qt -#include <QtCore/QAbstractListModel> - -//Ring -namespace Video { - class Resolution; - class Rate; - class Device; -} -class VideoChannelPrivate; - -namespace Video { - -///@typedef Channel A channel available in a Device -class LIB_EXPORT Channel : public QAbstractListModel -{ - //Only Video::Device can add resolutions - friend class Video::Device; -public: - QString name() const; - Video::Resolution* activeResolution(); - QList<Video::Resolution*> validResolutions() const; - Video::Device* device() const; - int relativeIndex(); - - bool setActiveResolution(Video::Resolution* res); - bool setActiveResolution(int idx); - - bool setActiveMode(int resIndex, int rateIndex); - - //Model - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - -private: - Channel(Video::Device* dev,const QString& name); - virtual ~Channel(); - - QScopedPointer<VideoChannelPrivate> d_ptr; -}; - -} diff --git a/src/video/configurationproxy.cpp b/src/video/configurationproxy.cpp deleted file mode 100644 index c9226c5e2e5d373aec2335000e891a43993a5516..0000000000000000000000000000000000000000 --- a/src/video/configurationproxy.cpp +++ /dev/null @@ -1,306 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "configurationproxy.h" - -//Qt -#include <QtCore/QIdentityProxyModel> -#include <QtCore/QAbstractItemModel> -#include <QtCore/QItemSelectionModel> - -//Ring -#include <video/sourcemodel.h> -#include <video/devicemodel.h> -#include <video/channel.h> -#include <video/resolution.h> -#include <video/rate.h> -#include <dbus/videomanager.h> - -namespace ConfigurationProxyPrivate { - static QIdentityProxyModel* m_spDeviceModel = nullptr; - static QIdentityProxyModel* m_spChannelModel = nullptr; - static QIdentityProxyModel* m_spResolutionModel= nullptr; - static QIdentityProxyModel* m_spRateModel = nullptr; - - static QItemSelectionModel* m_spDeviceSelectionModel = nullptr; - static QItemSelectionModel* m_spChannelSelectionModel = nullptr; - static QItemSelectionModel* m_spResolutionSelectionModel= nullptr; - static QItemSelectionModel* m_spRateSelectionModel = nullptr; - - static Video::SourceModel* m_sourceModel = nullptr; - - //Helper - static Video::Device* currentDevice (); - static Video::Channel* currentChannel (); - static Video::Resolution* currentResolution(); -// static Video::Rate* currentRate (); - - static void changeDevice (); - static void changeChannel (); - static void changeResolution(); - static void changeRate (); - - void updateDeviceSelection (); - void updateChannelSelection (); - void updateResolutionSelection(); - void updateRateSelection (); -} - -QAbstractItemModel& Video::ConfigurationProxy::deviceModel() -{ - if (!ConfigurationProxyPrivate::m_spDeviceModel) { - ConfigurationProxyPrivate::m_spDeviceModel = new QIdentityProxyModel(ConfigurationProxyPrivate::m_sourceModel); - ConfigurationProxyPrivate::m_spDeviceModel->setSourceModel(&Video::DeviceModel::instance()); - ConfigurationProxyPrivate::updateDeviceSelection(); - } - return *ConfigurationProxyPrivate::m_spDeviceModel; -} - -static Video::Device* ConfigurationProxyPrivate::currentDevice() -{ - return Video::DeviceModel::instance().Video::DeviceModel::instance().activeDevice(); -} - -static Video::Channel* ConfigurationProxyPrivate::currentChannel() -{ - if (Video::DeviceModel::instance().activeDevice() - && Video::DeviceModel::instance().activeDevice()->activeChannel()) - return Video::DeviceModel::instance().activeDevice()->activeChannel(); - - return nullptr; -} - -static Video::Resolution* ConfigurationProxyPrivate::currentResolution() -{ - if (Video::DeviceModel::instance().activeDevice() - && Video::DeviceModel::instance().activeDevice()->activeChannel() - && Video::DeviceModel::instance().activeDevice()->activeChannel()->activeResolution() - ) - return Video::DeviceModel::instance().activeDevice()->activeChannel()->activeResolution(); - return nullptr; -} - -/*static Video::Rate* ConfigurationProxyPrivate::currentRate() -{ - if (Video::DeviceModel::instance().activeDevice() - && Video::DeviceModel::instance().activeDevice()->activeChannel() - && Video::DeviceModel::instance().activeDevice()->activeChannel()->activeResolution() - ) - return Video::DeviceModel::instance().activeDevice()->activeChannel()->activeResolution()->activeRate(); - - return nullptr; -}*/ - -void ConfigurationProxyPrivate::changeDevice() -{ - Video::ConfigurationProxy::deviceSelectionModel(); - - Video::DeviceModel::instance().setActive(ConfigurationProxyPrivate::m_spDeviceSelectionModel->currentIndex()); - - reinterpret_cast<QIdentityProxyModel&>(Video::ConfigurationProxy::channelModel()).setSourceModel(ConfigurationProxyPrivate::currentDevice()); - changeChannel(); -} - -void ConfigurationProxyPrivate::changeChannel() -{ - Video::ConfigurationProxy::channelSelectionModel(); - - Video::Device* dev = ConfigurationProxyPrivate::currentDevice(); - - if (dev) - dev->setActiveChannel(ConfigurationProxyPrivate::m_spChannelSelectionModel->currentIndex().row()); - - reinterpret_cast<QIdentityProxyModel&>(Video::ConfigurationProxy::resolutionModel()).setSourceModel(ConfigurationProxyPrivate::currentChannel()); - - updateChannelSelection(); - - changeResolution(); -} - -void ConfigurationProxyPrivate::changeResolution() -{ - Video::ConfigurationProxy::resolutionSelectionModel(); - - Video::Channel* chan = ConfigurationProxyPrivate::currentChannel(); - - if (chan) - chan->setActiveResolution(ConfigurationProxyPrivate::m_spResolutionSelectionModel->currentIndex().row()); - - reinterpret_cast<QIdentityProxyModel&>(Video::ConfigurationProxy::rateModel()).setSourceModel(ConfigurationProxyPrivate::currentResolution()); - - updateResolutionSelection(); - - changeRate(); -} - -void ConfigurationProxyPrivate::changeRate() -{ - Video::ConfigurationProxy::rateSelectionModel(); - - Video::Resolution* res = ConfigurationProxyPrivate::currentResolution(); - - if (res) - res->setActiveRate(ConfigurationProxyPrivate::m_spRateSelectionModel->currentIndex().row()); - - updateRateSelection(); -} - -void ConfigurationProxyPrivate::updateDeviceSelection() -{ - if (ConfigurationProxyPrivate::m_spDeviceModel) { - const QModelIndex& idx = ConfigurationProxyPrivate::m_spDeviceModel->index(Video::DeviceModel::instance().activeIndex(),0); - if (idx.row() != Video::ConfigurationProxy::deviceSelectionModel().currentIndex().row()) - Video::ConfigurationProxy::deviceSelectionModel().setCurrentIndex(idx , QItemSelectionModel::ClearAndSelect); - } -} - -void ConfigurationProxyPrivate::updateChannelSelection() -{ - Video::Device* dev = ConfigurationProxyPrivate::currentDevice(); - if (dev) { - Video::Channel* chan = dev->activeChannel(); - if (chan) { - const QModelIndex& newIdx = dev->index(chan->relativeIndex(),0); - if (newIdx.row() != Video::ConfigurationProxy::channelSelectionModel().currentIndex().row()) - Video::ConfigurationProxy::channelSelectionModel().setCurrentIndex(newIdx, QItemSelectionModel::ClearAndSelect ); - } - } -} - -void ConfigurationProxyPrivate::updateResolutionSelection() -{ - Video::Channel* chan = ConfigurationProxyPrivate::currentChannel(); - if (chan) { - Video::Resolution* res = chan->activeResolution(); - if (res) { - const QModelIndex& newIdx = chan->index(res->relativeIndex(),0); - if (newIdx.row() != Video::ConfigurationProxy::resolutionSelectionModel().currentIndex().row()) - Video::ConfigurationProxy::resolutionSelectionModel().setCurrentIndex(newIdx, QItemSelectionModel::ClearAndSelect); - } - } -} - -void ConfigurationProxyPrivate::updateRateSelection() -{ - Video::Resolution* res = ConfigurationProxyPrivate::currentResolution(); - if (res) { - Video::Rate* rate = res->activeRate(); - if (rate) { - const QModelIndex& newIdx = res->index(rate->relativeIndex(),0); - if (newIdx.row() != Video::ConfigurationProxy::rateSelectionModel().currentIndex().row()) - Video::ConfigurationProxy::rateSelectionModel().setCurrentIndex(newIdx, QItemSelectionModel::ClearAndSelect); - } - } -} - -QAbstractItemModel& Video::ConfigurationProxy::channelModel() -{ - if (!ConfigurationProxyPrivate::m_spChannelModel) { - ConfigurationProxyPrivate::m_spChannelModel = new QIdentityProxyModel(ConfigurationProxyPrivate::m_sourceModel); - Video::Device* dev = ConfigurationProxyPrivate::currentDevice(); - if (dev) { - ConfigurationProxyPrivate::m_spChannelModel->setSourceModel(dev); - } - } - return *ConfigurationProxyPrivate::m_spChannelModel; -} - -QAbstractItemModel& Video::ConfigurationProxy::resolutionModel() -{ - if (!ConfigurationProxyPrivate::m_spResolutionModel) { - ConfigurationProxyPrivate::m_spResolutionModel = new QIdentityProxyModel(ConfigurationProxyPrivate::m_sourceModel); - Video::Channel* chan = ConfigurationProxyPrivate::currentChannel(); - if (chan) { - ConfigurationProxyPrivate::m_spResolutionModel->setSourceModel(chan); - } - } - return *ConfigurationProxyPrivate::m_spResolutionModel; -} - -QAbstractItemModel& Video::ConfigurationProxy::rateModel() -{ - if (!ConfigurationProxyPrivate::m_spRateModel) { - ConfigurationProxyPrivate::m_spRateModel = new QIdentityProxyModel(ConfigurationProxyPrivate::m_sourceModel); - ConfigurationProxyPrivate::m_spRateModel->setSourceModel(ConfigurationProxyPrivate::currentResolution()); - } - return *ConfigurationProxyPrivate::m_spRateModel; -} - -QItemSelectionModel& Video::ConfigurationProxy::deviceSelectionModel() -{ - if (!ConfigurationProxyPrivate::m_spDeviceSelectionModel) { - ConfigurationProxyPrivate::m_spDeviceSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spDeviceModel); - - ConfigurationProxyPrivate::updateDeviceSelection(); - - //Can happen if a device is removed - QObject::connect(&Video::DeviceModel::instance(), &Video::DeviceModel::currentIndexChanged,[](int idx) { - ConfigurationProxyPrivate::m_spDeviceSelectionModel->setCurrentIndex(ConfigurationProxyPrivate::m_spDeviceModel->index(idx,0), QItemSelectionModel::ClearAndSelect ); - }); - - QObject::connect(ConfigurationProxyPrivate::m_spDeviceSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeDevice); - } - return *ConfigurationProxyPrivate::m_spDeviceSelectionModel; -} - -QItemSelectionModel& Video::ConfigurationProxy::channelSelectionModel() -{ - if (!ConfigurationProxyPrivate::m_spChannelSelectionModel) { - ConfigurationProxyPrivate::m_spChannelSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spChannelModel); - - ConfigurationProxyPrivate::updateChannelSelection(); - - QObject::connect(ConfigurationProxyPrivate::m_spChannelSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeChannel); - } - return *ConfigurationProxyPrivate::m_spChannelSelectionModel; -} - -QItemSelectionModel& Video::ConfigurationProxy::resolutionSelectionModel() -{ - if (!ConfigurationProxyPrivate::m_spResolutionSelectionModel) { - ConfigurationProxyPrivate::m_spResolutionSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spResolutionModel); - - ConfigurationProxyPrivate::updateResolutionSelection(); - - QObject::connect(ConfigurationProxyPrivate::m_spResolutionSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeResolution); - } - return *ConfigurationProxyPrivate::m_spResolutionSelectionModel; -} - -QItemSelectionModel& Video::ConfigurationProxy::rateSelectionModel() -{ - if (!ConfigurationProxyPrivate::m_spRateSelectionModel) { - ConfigurationProxyPrivate::m_spRateSelectionModel = new QItemSelectionModel(ConfigurationProxyPrivate::m_spRateModel); - - ConfigurationProxyPrivate::updateRateSelection(); - - QObject::connect(ConfigurationProxyPrivate::m_spRateSelectionModel,&QItemSelectionModel::currentChanged, &ConfigurationProxyPrivate::changeRate); - } - return *ConfigurationProxyPrivate::m_spRateSelectionModel; -} - -bool Video::ConfigurationProxy::getDecodingAccelerated() -{ - VideoManagerInterface& interface = VideoManager::instance(); - return interface.getDecodingAccelerated(); -} - -void Video::ConfigurationProxy::setDecodingAccelerated(bool state) -{ - VideoManagerInterface& interface = VideoManager::instance(); - interface.setDecodingAccelerated(state); -} diff --git a/src/video/configurationproxy.h b/src/video/configurationproxy.h deleted file mode 100644 index f942ca2da02ddc37a62b768b27eb233b0a33cd19..0000000000000000000000000000000000000000 --- a/src/video/configurationproxy.h +++ /dev/null @@ -1,49 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2015-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -class QAbstractItemModel; -class QItemSelectionModel; - -namespace Video { - -/** - * This class is used to simplify the configuration process. - * Currently, every devices have their own model tree. This - * proxy flatten the three to the clients don't have to - * implement the managing logic. - */ -class LIB_EXPORT ConfigurationProxy { -public: - static QAbstractItemModel& deviceModel (); - static QAbstractItemModel& channelModel (); - static QAbstractItemModel& resolutionModel(); - static QAbstractItemModel& rateModel (); - - static QItemSelectionModel& deviceSelectionModel (); - static QItemSelectionModel& channelSelectionModel (); - static QItemSelectionModel& resolutionSelectionModel(); - static QItemSelectionModel& rateSelectionModel (); - - static bool getDecodingAccelerated(); - static void setDecodingAccelerated(bool state); -}; - -} //namespace Video diff --git a/src/video/device.cpp b/src/video/device.cpp deleted file mode 100644 index 2e48d2be625b39beb5566dd92984ada3d5c53b1e..0000000000000000000000000000000000000000 --- a/src/video/device.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "device.h" - -//Qt -#include <QtCore/QTimer> - -//Ring -#include "../dbus/videomanager.h" -#include "devicemodel.h" -#include "resolution.h" -#include "rate.h" -#include "channel.h" -#include "renderer.h" -#include "previewmanager.h" - -//Ring private -#include "../private/videochannel_p.h" -#include "../private/videodevice_p.h" -#include "../private/videorate_p.h" -#include "../private/videoresolution_p.h" -#include "../private/videorenderermanager.h" - -VideoDevicePrivate::VideoDevicePrivate(Video::Device* parent) : QObject(parent),m_pCurrentChannel(nullptr),m_RequireSave(false),q_ptr(parent) -{ -} - -///Constructor -Video::Device::Device(const QString &id) : QAbstractListModel(nullptr), -d_ptr(new VideoDevicePrivate(this)) -{ - d_ptr->m_DeviceId = id; - VideoManagerInterface& interface = VideoManager::instance(); - MapStringMapStringVectorString cap = interface.getCapabilities(id); - QMapIterator<QString, MapStringVectorString> channels(cap); - while (channels.hasNext()) { - channels.next(); - - Video::Channel* chan = new Video::Channel(this,channels.key()); - d_ptr->m_lChannels << chan; - QList<Video::Resolution*> validResolutions; - - QMapIterator<QString, VectorString> resolutions(channels.value()); - while (resolutions.hasNext()) { - resolutions.next(); - - Video::Resolution* res = new Video::Resolution(resolutions.key(),chan); - validResolutions << res; - - foreach(const QString& rate, resolutions.value()) { - Video::Rate* r = new Video::Rate(res,rate); - if (!res->d_ptr->m_lValidRates.contains(r)) { - res->d_ptr->m_lValidRates << r; - } - } - - // Sort rates in decreasing order. - qSort(res->d_ptr->m_lValidRates.begin(), - res->d_ptr->m_lValidRates.end(), - [](Video::Rate* rateA, Video::Rate* rateB) { - return rateA->name().toInt() < rateB->name().toInt(); - }); - } - - // Sort resolutions by size area. - qSort(validResolutions.begin(), - validResolutions.end(), - [](Video::Resolution* resA, Video::Resolution* resB) { - return resA->width() * resA->height() > resB->width() * resB->height(); - }); - chan->d_ptr->m_lValidResolutions = validResolutions; - } -} - -///Destructor -Video::Device::~Device() -{ -// delete d_ptr; -} - -QVariant Video::Device::data( const QModelIndex& index, int role) const -{ - if (index.isValid() && role == Qt::DisplayRole && d_ptr->m_lChannels.size() > index.row()) { - return d_ptr->m_lChannels[index.row()]->name(); - } - return QVariant(); -} - -int Video::Device::rowCount( const QModelIndex& parent) const -{ - return (parent.isValid())?0:d_ptr->m_lChannels.size(); -} - -Qt::ItemFlags Video::Device::flags( const QModelIndex& idx) const -{ - if (idx.column() == 0) - return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return QAbstractItemModel::flags(idx); -} - -bool Video::Device::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -// int Video::Device::relativeIndex() { -// return m_pDevice->channelList().indexOf(this); -// } - -///Get the valid channel list -QList<Video::Channel*> Video::Device::channelList() const -{ - return d_ptr->m_lChannels; -} - -///Save the current settings -void Video::Device::save() -{ - if (!d_ptr->m_RequireSave) { - d_ptr->m_RequireSave = true; - //A little delay won't hurt - QTimer::singleShot(100,d_ptr.data(),SLOT(saveIdle())); - } -} - -///Get the device id -const QString Video::Device::id() const -{ - return d_ptr->m_DeviceId; -} - -///Get the device name -const QString Video::Device::name() const -{ - VideoManagerInterface& interface = VideoManager::instance(); - return QMap<QString,QString>(interface.getSettings(d_ptr->m_DeviceId))[VideoDevicePrivate::PreferenceNames::NAME];; -} - -///Is this device the default one -bool Video::Device::isActive() const -{ - return Video::DeviceModel::instance().activeDevice() == this; -} - -bool Video::Device::setActiveChannel(Video::Channel* chan) -{ - if ((!chan) || (d_ptr->m_lChannels.indexOf(chan) == -1)) { - qWarning() << "Trying to set an invalid channel" << (chan?chan->name():"NULL") << "for" << id(); - return false; - } - - if (d_ptr->m_pCurrentChannel == chan) - return false; - - d_ptr->m_pCurrentChannel = chan; - save(); - return true; -} - -bool Video::Device::setActiveChannel(int idx) -{ - if (idx < 0 || idx >= d_ptr->m_lChannels.size()) return false; - return setActiveChannel(d_ptr->m_lChannels[idx]); -} - -Video::Channel* Video::Device::activeChannel() const -{ - if (!d_ptr->m_pCurrentChannel) { - VideoManagerInterface& interface = VideoManager::instance(); - const QString chan = QMap<QString,QString>(interface.getSettings(d_ptr->m_DeviceId))[VideoDevicePrivate::PreferenceNames::CHANNEL]; - foreach(Video::Channel* c, d_ptr->m_lChannels) { - if (c->name() == chan) { - d_ptr->m_pCurrentChannel = c; - break; - } - } - } - if (!d_ptr->m_pCurrentChannel && d_ptr->m_lChannels.size()) { - d_ptr->m_pCurrentChannel = d_ptr->m_lChannels[0]; - } - return d_ptr->m_pCurrentChannel; -} - -void VideoDevicePrivate::saveIdle() -{ - m_RequireSave = false; - - //In case new (unsupported) fields are added, merge with existing - VideoManagerInterface& interface = VideoManager::instance(); - MapStringString pref = interface.getSettings(m_DeviceId); - - Video::Channel* chan = q_ptr->activeChannel(); - - if (!chan) { - qWarning() << "Saving video failed: Invalid channel"; - return; - } - - Video::Resolution* res = chan->activeResolution(); - - if (!res) { - qWarning() << "Saving video failed: Invalid resolution"; - return; - } - - Video::Rate* rate = res->activeRate(); - - if (!rate) { - qWarning() << "Saving video failed: Invalid rate"; - return; - } - - pref[VideoDevicePrivate::PreferenceNames::CHANNEL] = chan->name (); - pref[VideoDevicePrivate::PreferenceNames::SIZE ] = res ->name (); - pref[VideoDevicePrivate::PreferenceNames::RATE ] = rate->name (); - interface.applySettings(m_DeviceId,pref); - - //If the preview is running, reload it - //doing this during a call will cause re-invite, this is unwanted - if (Video::PreviewManager::instance().isPreviewing() && VideoRendererManager::instance().size() == 1) { - Video::PreviewManager::instance().stopPreview(); - Video::PreviewManager::instance().startPreview(); - } -} diff --git a/src/video/device.h b/src/video/device.h deleted file mode 100644 index c8627d83f4480b7875e76b5032e2fdc510d0d30e..0000000000000000000000000000000000000000 --- a/src/video/device.h +++ /dev/null @@ -1,98 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> -#include <QtCore/QAbstractListModel> - -//Qt -#include <QStringList> -#include <QtCore/QSize> - -//Ring -namespace Video { - class Renderer; - class Resolution; - class Rate; - class Channel; - class Device; - class Model; - class Manager; - class DeviceModel; - class ManagerPrivate; -} - -class VideoDevicePrivate; - -namespace Video { - - -///Device: V4L devices used to record video for video call -class LIB_EXPORT Device : public QAbstractListModel { - Q_OBJECT - friend class VideoRendererManager; - friend class VideoRendererManagerPrivate; - friend class Video::DeviceModel; - friend class VideoDevicePrivate; - - //Need to access the PreferenceNames table - friend class Video::Channel; - friend class Video::Resolution; - public: - - //Constants - constexpr static const char* NONE = ""; - - //Model - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - - //Getter - QList<Channel*> channelList () const; - Video::Channel* activeChannel () const; - const QString id () const; - const QString name () const; - bool isActive () const; - - //Static getter - - //Setter - bool setActiveChannel(Video::Channel* chan); - bool setActiveChannel(int idx); - - //Mutator - void save(); - - private: - //Constructor - explicit Device(const QString& id); - virtual ~Device(); - - QScopedPointer<VideoDevicePrivate> d_ptr; - - - Q_SIGNALS: - void renderingStarted(Video::Renderer*); - void renderingStopped(Video::Renderer*); - void renderStateChanged(bool state); -}; - -} - diff --git a/src/video/devicemodel.cpp b/src/video/devicemodel.cpp deleted file mode 100644 index 34a3ec89eb02491e3aa7cf3df2a585a5b1cffe55..0000000000000000000000000000000000000000 --- a/src/video/devicemodel.cpp +++ /dev/null @@ -1,242 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "devicemodel.h" - -//Qt -#include <QtCore/QCoreApplication> -#include <QtCore/QTimer> - -//Ring -#include "device.h" -#include <call.h> -#include <account.h> -#include <video/previewmanager.h> -#include "../dbus/videomanager.h" -#include "../private/videorenderermanager.h" - -namespace Video { -class DeviceModelPrivate : public QObject -{ - Q_OBJECT -public: - DeviceModelPrivate(); - - //Attrbutes - QHash<QString,Video::Device*> m_hDevices ; - QList<Video::Device*> m_lDevices ; - Video::Device* m_pDummyDevice ; - Video::Device* m_pActiveDevice; - -private Q_SLOTS: - void idleReload(); -}; -} - -Video::DeviceModelPrivate::DeviceModelPrivate() : m_pDummyDevice(nullptr),m_pActiveDevice(nullptr) -{ -} - -/// -void Video::DeviceModelPrivate::idleReload() -{ - DeviceModel::instance().setActive(DeviceModel::instance().activeDevice()); -} - -///Constructor -Video::DeviceModel::DeviceModel() : QAbstractListModel(QCoreApplication::instance()), -d_ptr(new Video::DeviceModelPrivate()) -{ - reload(); - VideoManagerInterface& interface = VideoManager::instance(); - connect(&interface, SIGNAL(deviceEvent()), this, SLOT(reload()), Qt::QueuedConnection); -} - -Video::DeviceModel& Video::DeviceModel::instance() -{ - static auto instance = new Video::DeviceModel; - return *instance; -} - -QHash<int,QByteArray> Video::DeviceModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - /*static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - }*/ - return roles; -} - -///Get data from the model -QVariant Video::DeviceModel::data( const QModelIndex& idx, int role) const -{ - if(idx.isValid() && idx.column() == 0 && role == Qt::DisplayRole && d_ptr->m_lDevices.size() > idx.row()) - return QVariant(d_ptr->m_lDevices[idx.row()]->id()); - return QVariant(); -} - -///The number of codec -int Video::DeviceModel::rowCount( const QModelIndex& par ) const -{ - Q_UNUSED(par) - return d_ptr->m_lDevices.size(); -} - -///Items flag -Qt::ItemFlags Video::DeviceModel::flags( const QModelIndex& idx ) const -{ - if (idx.column() == 0) - return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return QAbstractItemModel::flags(idx); -} - -///Set the codec data (codecs can't be added or removed that way) -bool Video::DeviceModel::setData(const QModelIndex& idx, const QVariant &value, int role) -{ - Q_UNUSED(idx) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -///Destructor -Video::DeviceModel::~DeviceModel() -{ - while (d_ptr->m_lDevices.size()) { - Video::Device* c = d_ptr->m_lDevices[0]; - d_ptr->m_lDevices.removeAt(0); - delete c; - } -// delete d_ptr; -} - -///Save the current model over dbus -void Video::DeviceModel::setActive(const QModelIndex& idx) -{ - if (idx.isValid() && d_ptr->m_lDevices.size() > idx.row()) { - VideoManagerInterface& interface = VideoManager::instance(); - interface.setDefaultDevice(d_ptr->m_lDevices[idx.row()]->id()); - d_ptr->m_pActiveDevice = d_ptr->m_lDevices[idx.row()]; - emit changed(); - emit currentIndexChanged(idx.row()); - - //If the only renderer is the preview, reload it - if (Video::PreviewManager::instance().isPreviewing() && ::VideoRendererManager::instance().size() == 1) { - Video::PreviewManager::instance().stopPreview(); - Video::PreviewManager::instance().startPreview(); - } - } -} - -///Convenience -void Video::DeviceModel::setActive(const int idx) -{ - setActive(index(idx,0,QModelIndex())); -} - - -void Video::DeviceModel::setActive(const Video::Device* device) -{ - VideoManagerInterface& interface = VideoManager::instance(); - - interface.setDefaultDevice(device?device->id():Video::Device::NONE); - d_ptr->m_pActiveDevice = const_cast<Video::Device*>(device); - emit changed(); - const int idx = d_ptr->m_lDevices.indexOf((Video::Device*)device); - emit currentIndexChanged(idx); -} - -void Video::DeviceModel::reload() -{ - QHash<QString,Video::Device*> devicesHash; - VideoManagerInterface& interface = VideoManager::instance(); - const QStringList deviceList = interface.getDeviceList(); - if (deviceList.size() == d_ptr->m_hDevices.size()) { - d_ptr->m_lDevices = d_ptr->m_hDevices.values(); - } - - foreach(const QString& deviceName,deviceList) { - if (!d_ptr->m_hDevices[deviceName]) { - devicesHash[deviceName] = new Video::Device(deviceName); - } - else { - devicesHash[deviceName] = d_ptr->m_hDevices[deviceName]; - } - } - - // remove all old devices - beginResetModel(); - foreach(Video::Device* dev, d_ptr->m_hDevices) { - if (dev && devicesHash.key(dev).isEmpty()) { - dev->deleteLater(); - } - } - d_ptr->m_pActiveDevice = nullptr; - d_ptr->m_hDevices.clear(); - - // add all new devices - d_ptr->m_hDevices = devicesHash; - d_ptr->m_lDevices = d_ptr->m_hDevices.values(); - endResetModel(); - - //Avoid a possible infinite loop by using a reload event - QTimer::singleShot(0,d_ptr.data(),SLOT(idleReload())); -} - - -Video::Device* Video::DeviceModel::activeDevice() const -{ - if (!d_ptr->m_pActiveDevice) { - VideoManagerInterface& interface = VideoManager::instance(); - const QString deId = interface.getDefaultDevice(); - if (!d_ptr->m_lDevices.size()) - const_cast<Video::DeviceModel*>(this)->reload(); - Video::Device* dev = d_ptr->m_hDevices[deId]; - - //Handling null everywhere is too long, better create a dummy device and - //log the event - if (!dev) { - if (!deId.isEmpty()) - qWarning() << "Requested unknown device" << deId; - if (!d_ptr->m_pDummyDevice) - d_ptr->m_pDummyDevice = new Video::Device("None"); - return d_ptr->m_pDummyDevice; - } - d_ptr->m_pActiveDevice = dev; - } - return d_ptr->m_pActiveDevice; -} - -int Video::DeviceModel::activeIndex() const -{ - return d_ptr->m_lDevices.indexOf(activeDevice()); -} - - -Video::Device* Video::DeviceModel::getDevice(const QString& devId) const -{ - return d_ptr->m_hDevices[devId]; -} - -QList<Video::Device*> Video::DeviceModel::devices() const -{ - return d_ptr->m_lDevices; -} - -#include <devicemodel.moc> diff --git a/src/video/devicemodel.h b/src/video/devicemodel.h deleted file mode 100644 index b3260590c389727b012a903a9815388a365f00f3..0000000000000000000000000000000000000000 --- a/src/video/devicemodel.h +++ /dev/null @@ -1,77 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> -#include <QtCore/QAbstractListModel> -#include <QtCore/QUrl> -#include <QtCore/QRect> -#include "device.h" - - -//Qt - - -namespace Video { - -class DeviceModelPrivate; - -///Abstract model for managing account video codec list -class LIB_EXPORT DeviceModel : public QAbstractListModel { - #pragma GCC diagnostic push - #pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" - Q_OBJECT - #pragma GCC diagnostic pop - -public: - //Private constructor, can only be called by 'Account' - explicit DeviceModel(); - virtual ~DeviceModel(); - - //Model functions - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - static DeviceModel& instance(); - - - Video::Device* activeDevice() const; - int activeIndex() const; - Video::Device* getDevice(const QString& devId) const; - QList<Video::Device*> devices() const; - -private: - const QScopedPointer<DeviceModelPrivate> d_ptr; - -public Q_SLOTS: - void setActive(const QModelIndex& idx); - void setActive(const int idx); - void setActive(const Video::Device* device); - void reload(); - -Q_SIGNALS: - void changed(); - void currentIndexChanged(int); - -}; - -} -Q_DECLARE_METATYPE(Video::DeviceModel*) diff --git a/src/video/previewmanager.cpp b/src/video/previewmanager.cpp deleted file mode 100644 index 7c07d243e8ddd87908c99aa18f4366d4f47baa67..0000000000000000000000000000000000000000 --- a/src/video/previewmanager.cpp +++ /dev/null @@ -1,66 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the Lesser GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -#include "previewmanager.h" - -#include "private/videorenderermanager.h" -#include "video/renderer.h" - -Video::PreviewManager& Video::PreviewManager::instance() -{ - static auto instance = new PreviewManager(); - return *instance; -} - -//Getters -bool Video::PreviewManager::isPreviewing() -{ - return ::VideoRendererManager::instance().isPreviewing(); -} - -Video::Renderer* Video::PreviewManager::previewRenderer() -{ - return ::VideoRendererManager::instance().previewRenderer(); -} - -Video::PreviewManager::PreviewManager() : QObject(&::VideoRendererManager::instance()) -{ - connect(&::VideoRendererManager::instance(), &::VideoRendererManager::previewStateChanged, [this](bool startStop) { - emit previewStateChanged(startStop); - }); - connect(&::VideoRendererManager::instance(), &::VideoRendererManager::previewStarted , [this](Video::Renderer* renderer) { - emit previewStarted(renderer); - }); - connect(&::VideoRendererManager::instance(), &::VideoRendererManager::previewStopped , [this](Video::Renderer* renderer) { - emit previewStopped(renderer); - }); -} - -Video::PreviewManager::~PreviewManager() -{ - -} - -void Video::PreviewManager::stopPreview() -{ - return ::VideoRendererManager::instance().stopPreview(); -} - -void Video::PreviewManager::startPreview() -{ - return ::VideoRendererManager::instance().startPreview(); -} diff --git a/src/video/previewmanager.h b/src/video/previewmanager.h deleted file mode 100644 index 7f076c762d3415d0b19e076a0de988e4d70c5b2b..0000000000000000000000000000000000000000 --- a/src/video/previewmanager.h +++ /dev/null @@ -1,64 +0,0 @@ -/****************************************************************************** - * Copyright (C) 2012-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser General Public License for more details. * - * * - * You should have received a copy of the Lesser GNU General Public License * - * along with this program. If not, see <http://www.gnu.org/licenses/>. * - *****************************************************************************/ -#pragma once - -#include <QtCore/QObject> - -#include <typedefs.h> - -namespace Video { - - class Renderer; - -/** - * This class is used to enable, disable and use the video preview. - * - * The preview can be embedded into video widgets or used for configuration. - */ -class LIB_EXPORT PreviewManager : public QObject -{ - Q_OBJECT - -public: - Q_PROPERTY(bool previewing READ isPreviewing NOTIFY previewStateChanged) - - //Singleton - static PreviewManager& instance(); - - //Getters - bool isPreviewing (); - Video::Renderer* previewRenderer(); - -private: - //Constructor - explicit PreviewManager(); - virtual ~PreviewManager(); - -public Q_SLOTS: - void stopPreview (); - void startPreview(); - -Q_SIGNALS: - ///The preview started/stopped - void previewStateChanged(bool startStop); - void previewStarted(Video::Renderer* renderer); - void previewStopped(Video::Renderer* renderer); -}; - -} - diff --git a/src/video/rate.cpp b/src/video/rate.cpp deleted file mode 100644 index 069c165d91050731966247f1f68e722c8b24a113..0000000000000000000000000000000000000000 --- a/src/video/rate.cpp +++ /dev/null @@ -1,44 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "rate.h" -#include "devicemodel.h" -#include "channel.h" -#include "resolution.h" -#include "../private/videorate_p.h" - -Video::Rate::Rate(const Video::Resolution* res,const QString& name) : - d_ptr(new RatePrivate()) -{ - d_ptr->m_Name = name; - d_ptr->m_pResolution = res; -} - -Video::Rate::~Rate() -{ - delete d_ptr; -} - -int Video::Rate::relativeIndex() -{ - return Video::DeviceModel::instance().activeDevice()->activeChannel()->activeResolution()->validRates().indexOf(this); -} - -QString Video::Rate::name() const -{ - return d_ptr->m_Name; -} diff --git a/src/video/rate.h b/src/video/rate.h deleted file mode 100644 index 5cbd181f9590cac3f35cce5d5aa12e003ec5f131..0000000000000000000000000000000000000000 --- a/src/video/rate.h +++ /dev/null @@ -1,51 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <typedefs.h> - -//Ring -namespace Video { - class Resolution; - class Device; -} - -class RatePrivate; - -namespace Video { - -///@typedef Rate The rate for a device -class LIB_EXPORT Rate -{ - //Can only be created by Video::Device - friend class Video::Device; - -public: - QString name() const; - int relativeIndex(); - -private: - Rate(const Video::Resolution* res,const QString& name); - virtual ~Rate(); - - RatePrivate* d_ptr; - Q_DECLARE_PRIVATE(Rate) -}; - -} - diff --git a/src/video/renderer.cpp b/src/video/renderer.cpp index 415354049ebf3cb3a74ae3b44d7e2f8da5a2bcde..c3921bc6aadade3be097b7cdc7491bf3d18b1ee2 100644 --- a/src/video/renderer.cpp +++ b/src/video/renderer.cpp @@ -77,5 +77,3 @@ void Video::Renderer::setSize(const QSize& size) const { d_ptr->m_pSize = size; } - -#include <renderer.moc> diff --git a/src/video/renderer.h b/src/video/renderer.h index 0ec961dd2aa134111203ffad462e6fc29f3b6474..c7f8384c6d79ced8358cb49cc8f3c5cf2e7cb8af 100644 --- a/src/video/renderer.h +++ b/src/video/renderer.h @@ -20,6 +20,7 @@ //Base #include <QtCore/QObject> +#include "api/newvideo.h" #include <typedefs.h> // Std @@ -31,8 +32,6 @@ class QMutex; struct AVFrame; -//Ring -#include "device.h" namespace Video { @@ -95,7 +94,7 @@ public: //Getters virtual bool isRendering () const; - virtual Frame currentFrame () const = 0; + virtual lrc::api::video::Frame currentFrame () const = 0; virtual QSize size () const; virtual QMutex* mutex () const; virtual ColorSpace colorSpace () const = 0; diff --git a/src/video/resolution.cpp b/src/video/resolution.cpp deleted file mode 100644 index 434fc6f736ed4e1a5a1ade36ac2e0e0c48b97293..0000000000000000000000000000000000000000 --- a/src/video/resolution.cpp +++ /dev/null @@ -1,161 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "resolution.h" - -//Ring -#include "../dbus/videomanager.h" -#include "channel.h" -#include "rate.h" -#include "device.h" - -//Ring private -#include "../private/videodevice_p.h" -#include "../private/videorate_p.h" -#include "../private/videoresolution_p.h" - -//Qt -#include <QtCore/QStringList> - -Video::Resolution::Resolution(const QString& size, Video::Channel* chan) -: QAbstractListModel(chan),d_ptr(new VideoResolutionPrivate()) -{ - Q_ASSERT(chan != nullptr); - - d_ptr->m_pChannel = chan; - d_ptr->m_pCurrentRate = nullptr; - - if (size.split('x').size() == 2) { - setWidth(size.split('x')[0].toInt()); - setHeight(size.split('x')[1].toInt()); - } -} - -Video::Resolution::~Resolution() -{ - delete d_ptr; -} - -const QString Video::Resolution::name() const -{ - return QString::number(width())+'x'+QString::number(height()); -} - -QVariant Video::Resolution::data( const QModelIndex& index, int role) const -{ - if (index.isValid() && role == Qt::DisplayRole && index.row() < d_ptr->m_lValidRates.size()) { - return d_ptr->m_lValidRates[index.row()]->name(); - } - return QVariant(); -} - -int Video::Resolution::rowCount( const QModelIndex& parent) const -{ - return (parent.isValid())?0:d_ptr->m_lValidRates.size(); -} - -Qt::ItemFlags Video::Resolution::flags( const QModelIndex& idx) const -{ - if (idx.column() == 0) - return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - return QAbstractItemModel::flags(idx); -} - -bool Video::Resolution::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -const QList<Video::Rate*> Video::Resolution::validRates() const { - return d_ptr->m_lValidRates; -} - -bool Video::Resolution::setActiveRate(Video::Rate* rate) { - if (!rate || (d_ptr->m_lValidRates.indexOf(rate) == -1)) { - qWarning() << "Trying to set an invalid rate: " << rate->name(); - return false; - } - - if (d_ptr->m_pCurrentRate == rate) - return false; - - d_ptr->m_pCurrentRate = rate; - d_ptr->m_pChannel->device()->save(); - return true; -} - -bool Video::Resolution::setActiveRate(int idx) -{ - if (idx >= d_ptr->m_lValidRates.size() || idx < 0) return false; - return setActiveRate(d_ptr->m_lValidRates[idx]); -} - -Video::Rate* Video::Resolution::activeRate() const -{ - if (!d_ptr->m_pChannel) { - qWarning() << "Trying to get the active rate of an unattached resolution"; - return nullptr; - } - if (!d_ptr->m_pCurrentRate && d_ptr->m_pChannel && d_ptr->m_pChannel->device()->isActive()) { - VideoManagerInterface& interface = VideoManager::instance(); - const QString rate = QMap<QString,QString>( - interface.getSettings(d_ptr->m_pChannel->device()->id()))[VideoDevicePrivate::PreferenceNames::RATE]; - foreach(Video::Rate* r, d_ptr->m_lValidRates) { - if (r->name() == rate) { - d_ptr->m_pCurrentRate = r; - break; - } - } - } - if ((!d_ptr->m_pCurrentRate) && d_ptr->m_lValidRates.size()) - d_ptr->m_pCurrentRate = d_ptr->m_lValidRates[0]; - - return d_ptr->m_pCurrentRate; -} - -int Video::Resolution::relativeIndex() const -{ - return d_ptr->m_pChannel?d_ptr->m_pChannel->validResolutions().indexOf(const_cast<Video::Resolution*>(this)):-1; -} - -int Video::Resolution::width() const -{ - return d_ptr->m_Size.width(); -} - -int Video::Resolution::height() const -{ - return d_ptr->m_Size.height(); -} - -QSize Video::Resolution::size() const -{ - return d_ptr->m_Size; -} - -void Video::Resolution::setWidth(int width) -{ - d_ptr->m_Size.setWidth(width); -} - -void Video::Resolution::setHeight(int height) -{ - d_ptr->m_Size.setHeight(height); -} diff --git a/src/video/resolution.h b/src/video/resolution.h deleted file mode 100644 index b10efd140e392ab99941323a5f0ba4221f345c80..0000000000000000000000000000000000000000 --- a/src/video/resolution.h +++ /dev/null @@ -1,74 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> -#include <QtCore/QSize> -#include <typedefs.h> - -namespace Video { - class Rate; - class Channel; - class Device; -} - -class VideoResolutionPrivate; - -namespace Video { - -///@struct Resolution Equivalent of "640x480" -class LIB_EXPORT Resolution : public QAbstractListModel { - Q_OBJECT - //Only Video::Device can add validated rates - friend class Video::Device; -public: - //Constructor - Resolution(const QString& size, Video::Channel* chan); - explicit Resolution(); - virtual ~Resolution(); - - //Getter - const QString name () const; - int height () const; - const QList<Video::Rate*> validRates () const; - int relativeIndex () const; - Video::Rate* activeRate () const; - int width () const; - QSize size () const; - - //Setters - bool setActiveRate( Video::Rate* rate ); - bool setActiveRate( int index ); - - //Setters - void setWidth(int width); - void setHeight(int height); - - //Model - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - - -private: - VideoResolutionPrivate* d_ptr; - -}; - -} diff --git a/src/video/sourcemodel.cpp b/src/video/sourcemodel.cpp deleted file mode 100644 index 74456cb1463d56cc15786970177daf4a3a59b7b4..0000000000000000000000000000000000000000 --- a/src/video/sourcemodel.cpp +++ /dev/null @@ -1,309 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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 "sourcemodel.h" -#include <QtCore/QUrl> -#include <QtCore/QCoreApplication> -#include "../dbus/videomanager.h" -#include "devicemodel.h" -#include <media_const.h> - -namespace Video { -class SourceModelPrivate : public QObject -{ - Q_OBJECT -public: - explicit SourceModelPrivate(SourceModel *parent); - - struct Display { - Display() : rect(0,0,0,0),index(0){} - QRect rect; - int index ; /* X11 display ID, usually 0 */ - }; - - QUrl m_CurrentFile; - Display m_Display; - int m_CurrentSelection; - QString m_CurrentSelectionId; // if the current selection is a camera, store the device id here - bool m_DeviceModelReloading; - -private: - SourceModel* q_ptr; - -private Q_SLOTS: - void devicesAboutToReload(); - void devicesReloaded(); -}; -} - -Video::SourceModelPrivate::SourceModelPrivate(SourceModel *parent) : QObject(parent), q_ptr(parent), -m_CurrentSelection(-1), m_DeviceModelReloading(false) -{ - connect(&Video::DeviceModel::instance(), &QAbstractItemModel::modelAboutToBeReset, this, &SourceModelPrivate::devicesAboutToReload); - connect(&Video::DeviceModel::instance(), &QAbstractItemModel::modelReset, this, &SourceModelPrivate::devicesReloaded); -} - -Video::SourceModel::SourceModel(QObject* parent) : QAbstractListModel(parent), -d_ptr(new Video::SourceModelPrivate(this)) -{ - d_ptr->m_Display.rect = QRect(0,0,0,0); - - // set the active device to the default one, if it exists - auto deviceIdx = Video::DeviceModel::instance().activeIndex(); - if (deviceIdx > -1) { - d_ptr->m_CurrentSelection = deviceIdx + ExtendedDeviceList::COUNT__; - d_ptr->m_CurrentSelectionId = Video::DeviceModel::instance().activeDevice()->id(); - } -} - -Video::SourceModel::~SourceModel() -{ - delete d_ptr; -} - -QHash<int,QByteArray> Video::SourceModel::roleNames() const -{ - static QHash<int, QByteArray> roles = QAbstractItemModel::roleNames(); - static bool initRoles = false; - if (!initRoles) { - initRoles = true; - - } - return roles; -} - -QVariant Video::SourceModel::data( const QModelIndex& index, int role ) const -{ - switch (index.row()) { - case ExtendedDeviceList::NONE: - switch(role) { - case Qt::DisplayRole: - return tr("NONE"); - }; - break; - case ExtendedDeviceList::SCREEN: - switch(role) { - case Qt::DisplayRole: - return tr("SCREEN"); - }; - break; - case ExtendedDeviceList::FILE: - switch(role) { - case Qt::DisplayRole: - return tr("FILE"); - }; - break; - default: - return Video::DeviceModel::instance().data(Video::DeviceModel::instance().index(index.row()-ExtendedDeviceList::COUNT__,0),role); - }; - return QVariant(); -} - -int Video::SourceModel::rowCount( const QModelIndex& parent ) const -{ - Q_UNUSED(parent) - return d_ptr->m_DeviceModelReloading ? - ExtendedDeviceList::COUNT__ : Video::DeviceModel::instance().rowCount() + ExtendedDeviceList::COUNT__; -} - -Qt::ItemFlags Video::SourceModel::flags( const QModelIndex& idx ) const -{ - switch (idx.row()) { - case ExtendedDeviceList::NONE : - case ExtendedDeviceList::SCREEN: - case ExtendedDeviceList::FILE : - return QAbstractItemModel::flags(idx) | Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; - break; - default: - return Video::DeviceModel::instance().flags(Video::DeviceModel::instance().index(idx.row()-ExtendedDeviceList::COUNT__,0)); - }; -} - -bool Video::SourceModel::setData( const QModelIndex& index, const QVariant &value, int role) -{ - Q_UNUSED(index) - Q_UNUSED(value) - Q_UNUSED(role) - return false; -} - -void Video::SourceModel::switchTo(const QModelIndex& idx) -{ - switchTo(idx.row()); -} - -///This model is designed for "live" switching rather than configuration -void Video::SourceModel::switchTo(const int idx) -{ - auto newIdx = idx > -1 ? idx : ExtendedDeviceList::NONE; - QString sep = DRing::Media::VideoProtocolPrefix::SEPARATOR; - switch (newIdx) { - case ExtendedDeviceList::NONE: - d_ptr->m_CurrentSelectionId = QString(); - VideoManager::instance().switchInput(DRing::Media::VideoProtocolPrefix::NONE); - break; - case ExtendedDeviceList::SCREEN: - d_ptr->m_CurrentSelectionId = QString(); - VideoManager::instance().switchInput(QString("%1%2:%3+%4,%5 %6x%7") - .arg(DRing::Media::VideoProtocolPrefix::DISPLAY) - .arg(sep) - .arg(d_ptr->m_Display.index) - .arg(d_ptr->m_Display.rect.x()) - .arg(d_ptr->m_Display.rect.y()) - .arg(d_ptr->m_Display.rect.width()) - .arg(d_ptr->m_Display.rect.height())); - break; - case ExtendedDeviceList::FILE: - d_ptr->m_CurrentSelectionId = QString(); - VideoManager::instance().switchInput( - !d_ptr->m_CurrentFile.isEmpty() ? QString("%1%2%3") - .arg(DRing::Media::VideoProtocolPrefix::FILE) - .arg(sep) - .arg(d_ptr->m_CurrentFile.toLocalFile()) - : DRing::Media::VideoProtocolPrefix::NONE - ); - break; - default: - d_ptr->m_CurrentSelectionId = Video::DeviceModel::instance().index(idx-ExtendedDeviceList::COUNT__,0).data(Qt::DisplayRole).toString(); - VideoManager::instance().switchInput(QString("%1%2%3") - .arg(DRing::Media::VideoProtocolPrefix::CAMERA) - .arg(sep) - .arg(d_ptr->m_CurrentSelectionId)); - break; - }; - d_ptr->m_CurrentSelection = newIdx; -} - -///Set the index of the currently used source -void Video::SourceModel::setUsedIndex(QString &deviceStr) -{ - int idx = 0; - //find out index here - if (deviceStr.length() <= 0) { - idx = ExtendedDeviceList::NONE; - } - else if (deviceStr.indexOf(DRing::Media::VideoProtocolPrefix::DISPLAY) == 0) { - // Look for the display string into the incoming device string - idx = ExtendedDeviceList::SCREEN; - } - else if (deviceStr.indexOf(DRing::Media::VideoProtocolPrefix::FILE) == 0) { - idx = ExtendedDeviceList::FILE; - } - else if (deviceStr.indexOf(DRing::Media::VideoProtocolPrefix::CAMERA) == 0) { - QString sep = DRing::Media::VideoProtocolPrefix::SEPARATOR; - auto fullPrefix = QString("%1%2") - .arg(DRing::Media::VideoProtocolPrefix::CAMERA) - .arg(DRing::Media::VideoProtocolPrefix::SEPARATOR); - Video::Device* dev = Video::DeviceModel::instance().getDevice(deviceStr.replace(fullPrefix,"")); - if (dev == nullptr) { - // Device not found we don't know what camera is used - idx = ExtendedDeviceList::NONE; - return; - } - - Video::DeviceModel::instance().setActive(dev); - idx = ExtendedDeviceList::COUNT__ + Video::DeviceModel::instance().activeIndex(); - } - else { - idx = ExtendedDeviceList::NONE; - } - - d_ptr->m_CurrentSelection = idx; -} - -void Video::SourceModel::switchTo(Video::Device* device) -{ - switchTo(getDeviceIndex(device)); -} - -Video::Device* Video::SourceModel::deviceAt(const QModelIndex& idx) const -{ - if (!idx.isValid()) return nullptr; - switch (idx.row()) { - case ExtendedDeviceList::NONE: - case ExtendedDeviceList::SCREEN: - case ExtendedDeviceList::FILE: - return nullptr; - default: - return Video::DeviceModel::instance().devices()[idx.row()-ExtendedDeviceList::COUNT__]; - }; -} - -int Video::SourceModel::activeIndex() const -{ - /* its possible for the saved selection to be invalid if the device model is in the process - * of being reloaded */ - return d_ptr->m_CurrentSelection >= rowCount() ? -1 : d_ptr->m_CurrentSelection; -} - -void Video::SourceModel::setFile(const QUrl& url) -{ - d_ptr->m_CurrentFile = url; - switchTo(ExtendedDeviceList::FILE); -} - -void Video::SourceModel::setDisplay(int index, QRect rect) -{ - d_ptr->m_Display.index = index ; - d_ptr->m_Display.rect = rect ; - switchTo(ExtendedDeviceList::SCREEN); -} - -int Video::SourceModel::getDeviceIndex(Video::Device* device) -{ - int index = Video::DeviceModel::instance().devices().indexOf(device); - return index > -1 ? ExtendedDeviceList::COUNT__ + index : -1; -} - -void Video::SourceModelPrivate::devicesAboutToReload() -{ - // are there any camera devices to reload? - if (q_ptr->rowCount() > SourceModel::ExtendedDeviceList::COUNT__) { - int first = SourceModel::ExtendedDeviceList::COUNT__; - int last = q_ptr->rowCount() - 1; - q_ptr->beginRemoveRows(QModelIndex(), first, last); - /* we keep the current selection until the device model is reloaded, so we can try to select - * the same one */ - m_DeviceModelReloading = true; - q_ptr->removeRows(first, last); - } -} - -void Video::SourceModelPrivate::devicesReloaded() -{ - // insert rows if we have any devices - if (Video::DeviceModel::instance().rowCount() > 0) { - int first = SourceModel::ExtendedDeviceList::COUNT__; - int last = SourceModel::ExtendedDeviceList::COUNT__ + Video::DeviceModel::instance().rowCount() - 1; - q_ptr->beginInsertRows(QModelIndex(), first, last); - m_DeviceModelReloading = false; - if (m_CurrentSelection >= SourceModel::ExtendedDeviceList::COUNT__) { - // the device order may have changed, try to get the same one as before - if (auto device = Video::DeviceModel::instance().getDevice(m_CurrentSelectionId)) { - m_CurrentSelection = q_ptr->getDeviceIndex(device); - } else { - m_CurrentSelectionId = QString(); - m_CurrentSelection = -1; - } - } - q_ptr->insertRows(first, last); - } else { - m_DeviceModelReloading = false; - } -} - -#include <sourcemodel.moc> diff --git a/src/video/sourcemodel.h b/src/video/sourcemodel.h deleted file mode 100644 index e1b18ccec8b4756b170a5f5a50b9c097252063f6..0000000000000000000000000000000000000000 --- a/src/video/sourcemodel.h +++ /dev/null @@ -1,69 +0,0 @@ -/**************************************************************************** - * Copyright (C) 2014-2019 Savoir-faire Linux Inc. * - * Author : Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> * - * * - * This library is free software; you can redistribute it and/or * - * modify it under the terms of the GNU Lesser General Public * - * License as published by the Free Software Foundation; either * - * version 2.1 of the License, or (at your option) any later version. * - * * - * This library 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 * - * Lesser 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/>. * - ***************************************************************************/ -#pragma once - -#include <QtCore/QAbstractListModel> -#include <QtCore/QRect> -#include <typedefs.h> - -//Ring - -namespace Video { - -class Device; -class SourceModelPrivate; - -//TODO qt5, use QIdentityProxyModel -class LIB_EXPORT SourceModel : public QAbstractListModel { - Q_OBJECT -public: - explicit SourceModel(QObject* parent = nullptr); - virtual ~SourceModel(); - - enum ExtendedDeviceList { - NONE , - SCREEN , - FILE , - COUNT__ - }; - virtual QVariant data ( const QModelIndex& index, int role = Qt::DisplayRole ) const override; - virtual int rowCount ( const QModelIndex& parent = QModelIndex() ) const override; - virtual Qt::ItemFlags flags ( const QModelIndex& index ) const override; - virtual bool setData ( const QModelIndex& index, const QVariant &value, int role) override; - virtual QHash<int,QByteArray> roleNames() const override; - - Device* deviceAt(const QModelIndex& idx) const; - - int activeIndex() const; - - int getDeviceIndex(Video::Device* device); - void setUsedIndex(QString& deviceStr); - -private: - Video::SourceModelPrivate* d_ptr; - Q_DECLARE_PRIVATE(SourceModel) - -public Q_SLOTS: - void switchTo(const QModelIndex& idx); - void switchTo(const int idx); - void switchTo(Video::Device* device); - void setFile(const QUrl& url); - void setDisplay(int index, QRect rect = QRect(0,0,0,0)); -}; - -}