From 98e4cc9cf1e666a209cc23d60ebcf2bb8185543c Mon Sep 17 00:00:00 2001 From: Emmanuel Lepage Vallee <emmanuel.lepage@savoirfairelinux.com> Date: Fri, 27 Feb 2015 18:33:34 +0000 Subject: [PATCH] Fully restore the ability to handle contacts and history This was required to move forward and implement certificate pinning This commit: * Fix the collection API * Implement Collection "supportedFeatures" filters * Improve support for DHT accounts Refs #66482 --- src/account.cpp | 20 ++++++++++ src/account.h | 5 ++- src/availableaccountmodel.cpp | 23 ++++++++--- src/availableaccountmodel.h | 2 +- src/call.cpp | 10 ++++- src/callmodel.cpp | 8 +++- src/collectionmanagerinterface.h | 8 ++-- src/collectionmanagerinterface.hpp | 61 +++++++++++++++++++++++++----- src/historymodel.cpp | 13 +++---- src/uri.cpp | 11 ++++++ src/uri.h | 11 ++++-- 11 files changed, 137 insertions(+), 35 deletions(-) diff --git a/src/account.cpp b/src/account.cpp index 47d6c73b..15f935fa 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -885,6 +885,26 @@ QVariant Account::roleData(int role) const #undef CAST +bool Account::supportScheme( URI::SchemeType type ) +{ + switch(type) { + case URI::SchemeType::NONE : + return true; + case URI::SchemeType::SIP : + case URI::SchemeType::SIPS : + if (protocol() == Account::Protocol::SIP) + return true; + case URI::SchemeType::IAX : + if (protocol() == Account::Protocol::IAX) + return true; + case URI::SchemeType::RING : + if (protocol() == Account::Protocol::RING) + return true; + } + return false; +} + + /***************************************************************************** * * * Setters * diff --git a/src/account.h b/src/account.h index 6a5c998a..f23a3550 100644 --- a/src/account.h +++ b/src/account.h @@ -29,6 +29,7 @@ class QString; //Ring #include "keyexchangemodel.h" #include "tlsmethodmodel.h" +#include "uri.h" #include "typedefs.h" class CredentialModel ; class RingToneModel ; @@ -295,7 +296,9 @@ class LIB_EXPORT Account : public QObject { RegistrationState registrationState () const; Protocol protocol () const; KeyExchangeModel::Type keyExchange () const; - QVariant roleData (int role) const; + + Q_INVOKABLE QVariant roleData ( int role ) const; + Q_INVOKABLE bool supportScheme( URI::SchemeType type ) ; //Setters void setId (const QByteArray& id ); diff --git a/src/availableaccountmodel.cpp b/src/availableaccountmodel.cpp index 4b59206c..e37a1fdb 100644 --- a/src/availableaccountmodel.cpp +++ b/src/availableaccountmodel.cpp @@ -26,6 +26,8 @@ //Ring #include "private/accountmodel_p.h" +#include "contactmethod.h" +#include "uri.h" class AvailableAccountModelPrivate : public QObject { @@ -38,7 +40,7 @@ public: static AvailableAccountModel* m_spInstance ; static void setPriorAccount ( const Account* account ); - static Account* firstRegisteredAccount( ); + static Account* firstRegisteredAccount( URI::SchemeType type = URI::SchemeType::NONE ); AvailableAccountModel* q_ptr; @@ -94,14 +96,19 @@ bool AvailableAccountModel::filterAcceptsRow(int source_row, const QModelIndex& ///Return the current account -Account* AvailableAccountModel::currentDefaultAccount() +Account* AvailableAccountModel::currentDefaultAccount(ContactMethod* method) { Account* priorAccount = AvailableAccountModelPrivate::m_spPriorAccount; - if(priorAccount && priorAccount->registrationState() == Account::RegistrationState::READY && priorAccount->isEnabled() ) { + URI::SchemeType type = (!method) ? URI::SchemeType::NONE : method->uri().schemeType(); + if(priorAccount + && priorAccount->registrationState() == Account::RegistrationState::READY + && priorAccount->isEnabled() + && (priorAccount->supportScheme(type)) + ) { return priorAccount; } else { - Account* a = AvailableAccountModelPrivate::firstRegisteredAccount(); + Account* a = AvailableAccountModelPrivate::firstRegisteredAccount(type); if (!a) a = AccountModel::instance()->getById(DRing::Account::ProtocolNames::IP2IP); @@ -127,10 +134,14 @@ void AvailableAccountModelPrivate::setPriorAccount(const Account* account) { } ///Get the first registerred account (default account) -Account* AvailableAccountModelPrivate::firstRegisteredAccount() +Account* AvailableAccountModelPrivate::firstRegisteredAccount(URI::SchemeType type) { for (Account* current : AccountModel::instance()->d_ptr->m_lAccounts) { - if(current && current->registrationState() == Account::RegistrationState::READY && current->isEnabled()) + if(current + && current->registrationState() == Account::RegistrationState::READY + && current->isEnabled() + && current->supportScheme(type) + ) return current; } return nullptr; diff --git a/src/availableaccountmodel.h b/src/availableaccountmodel.h index 2f4b20fc..d71c56f3 100644 --- a/src/availableaccountmodel.h +++ b/src/availableaccountmodel.h @@ -49,7 +49,7 @@ public: QItemSelectionModel* selectionModel() const; //Getter - static Account* currentDefaultAccount(); + static Account* currentDefaultAccount(ContactMethod* method = nullptr); //Singleton static AvailableAccountModel* instance(); diff --git a/src/call.cpp b/src/call.cpp index 543c99d1..b1eeaa24 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -1250,7 +1250,7 @@ void CallPrivate::call() qDebug() << "account = " << m_Account; if(!m_Account) { qDebug() << "Account is not set, taking the first registered."; - m_Account = AvailableAccountModel::currentDefaultAccount(); + m_Account = AvailableAccountModel::currentDefaultAccount(m_pDialNumber); } //Calls to empty URI should not be allowed, dring will go crazy if ((!m_pDialNumber) || m_pDialNumber->uri().isEmpty()) { @@ -1276,6 +1276,14 @@ void CallPrivate::call() //Warning: m_pDialNumber can become nullptr when linking directly m_DringId = callManager.placeCall(m_Account->id(), m_pDialNumber->uri()); + //This can happen when the daemon cannot allocate memory + if (m_DringId.isEmpty()) { + changeCurrentState(Call::State::FAILURE); + qWarning() << "Creating the call to" << m_pDialNumber->uri() << "failed"; + m_DringId = "FAILED"; //TODO once the ABORTED state is implemented, use it + return; + } + CallModel::instance()->registerCall(q_ptr); setObjectName("Call:"+m_DringId); diff --git a/src/callmodel.cpp b/src/callmodel.cpp index ca433c19..73f8f578 100644 --- a/src/callmodel.cpp +++ b/src/callmodel.cpp @@ -1037,8 +1037,12 @@ void CallModelPrivate::slotCallStateChanged(const QString& callID, const QString //Add to history if (call->lifeCycleState() == Call::LifeCycleState::FINISHED) { - //HistoryModel::instance()->add(call); - //FIXME check all collection with a "::ADD" filter and add the call + if (!call->collection()) { + foreach (CollectionInterface* backend, HistoryModel::instance()->collections(CollectionInterface::ADD)) { + if (backend->editor<Call>()->addNew(call)) + call->setCollection(backend); + } + } } emit q_ptr->callStateChanged(call,previousState); diff --git a/src/collectionmanagerinterface.h b/src/collectionmanagerinterface.h index 626ed064..7611d2cd 100644 --- a/src/collectionmanagerinterface.h +++ b/src/collectionmanagerinterface.h @@ -95,12 +95,12 @@ public: T2* addBackend(Ts... args, const LoadOptions options = LoadOptions::NONE); /// Do this manager have active collections - virtual bool hasEnabledCollections () const final; - virtual bool hasCollections () const final; + virtual bool hasEnabledCollections (CollectionInterface::SupportedFeatures features = CollectionInterface::SupportedFeatures::NONE) const final; + virtual bool hasCollections (CollectionInterface::SupportedFeatures features = CollectionInterface::SupportedFeatures::NONE) const final; /// List all Collections - virtual const QVector< CollectionInterface* > collections () const final; - virtual const QVector< CollectionInterface* > enabledCollections() const final; + virtual const QVector< CollectionInterface* > collections (CollectionInterface::SupportedFeatures features = CollectionInterface::SupportedFeatures::NONE) const final; + virtual const QVector< CollectionInterface* > enabledCollections(CollectionInterface::SupportedFeatures features = CollectionInterface::SupportedFeatures::NONE) const final; ///Enable / disable a collection virtual bool enableBackend( CollectionInterface* collection, bool enabled) final; diff --git a/src/collectionmanagerinterface.hpp b/src/collectionmanagerinterface.hpp index 39767768..d9e08314 100644 --- a/src/collectionmanagerinterface.hpp +++ b/src/collectionmanagerinterface.hpp @@ -33,6 +33,7 @@ public: CollectionManagerInterface<T>* i_ptr; CollectionMediator<T>* itemMediator() const; + inline const QVector< CollectionInterface* > filterCollections(QVector< CollectionInterface* > in, CollectionInterface::SupportedFeatures features) const; }; template<class T> @@ -80,28 +81,70 @@ CollectionManagerInterface<T>::CollectionManagerInterface(QAbstractItemModel* se } template<class T> -const QVector< CollectionInterface* > CollectionManagerInterface<T>::collections() const +const QVector< CollectionInterface* > CollectionManagerInterfacePrivate<T>::filterCollections(QVector< CollectionInterface* > in, CollectionInterface::SupportedFeatures features) const { - return d_ptr->m_lCollections; + 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>::enabledCollections() const +const QVector< CollectionInterface* > CollectionManagerInterface<T>::collections(CollectionInterface::SupportedFeatures features) const { - return d_ptr->m_lEnabledCollections; + if (features != CollectionInterface::SupportedFeatures::NONE) + return d_ptr->filterCollections(d_ptr->m_lCollections, features); + else + return d_ptr->m_lCollections; } -/// Do this manager have active collections +/** + * 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> -bool CollectionManagerInterface<T>::hasEnabledCollections() const +const QVector< CollectionInterface* > CollectionManagerInterface<T>::enabledCollections(CollectionInterface::SupportedFeatures features) const { - return d_ptr->m_lEnabledCollections.size(); + 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>::hasCollections() const +bool CollectionManagerInterface<T>::hasEnabledCollections(CollectionInterface::SupportedFeatures features) const { - return d_ptr->m_lCollections.size(); + 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(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> diff --git a/src/historymodel.cpp b/src/historymodel.cpp index a58fa9b5..fb760099 100644 --- a/src/historymodel.cpp +++ b/src/historymodel.cpp @@ -325,18 +325,17 @@ void HistoryModelPrivate::add(Call* call) LastUsedNumberModel::instance()->addCall(call); emit q_ptr->historyChanged(); + /* // Loop until it find a compatible backend //HACK only support a single active history backend if (!call->collection()) { - foreach (CollectionInterface* backend, q_ptr->collections()) { - if (backend->supportedFeatures() & CollectionInterface::ADD) { - if (backend->editor<Call>()->addNew(call)) { - call->setCollection(backend); - break; - } + foreach (CollectionInterface* backend, q_ptr->collections(CollectionInterface::ADD)) { + if (backend->editor<Call>()->addNew(call)) { + call->setCollection(backend); + break; } } - } + }*/ } ///Set if the history has a limit diff --git a/src/uri.cpp b/src/uri.cpp index 943129e5..b745bd63 100644 --- a/src/uri.cpp +++ b/src/uri.cpp @@ -131,9 +131,20 @@ bool URI::hasHostname() const return !d_ptr->m_Hostname.isEmpty(); } +/** + * Return the URI SchemeType + */ +URI::SchemeType URI::schemeType() const +{ + if (!d_ptr->m_Parsed) + const_cast<URI*>(this)->d_ptr->parse(); + return d_ptr->m_HeaderType; +} + ///Keep a cache of the values to avoid re-parsing them void URIPrivate::parse() { + //TODO DHT hashes have 40 chars or 45 with sips:/ring: is set if (q_ptr->indexOf('@') != -1) { const QStringList split = q_ptr->split('@'); m_Hostname = split[1];//split[1].left(split[1].size()) diff --git a/src/uri.h b/src/uri.h index d4119c7d..f3353b47 100644 --- a/src/uri.h +++ b/src/uri.h @@ -85,6 +85,7 @@ public: SIP , SIPS , IAX , + RING , }; ///Strings associated with SchemeType @@ -93,6 +94,7 @@ public: /*SIP = */ "sip:" , /*SIPS = */ "sips:", /*IAX = */ "iax:" , + /*RING = */ "ring:", }; /** @@ -111,10 +113,11 @@ public: sctp , /*!< */ }; - QString hostname () const; - QString fullUri () const; - QString userinfo () const; - bool hasHostname() const; + QString hostname () const; + QString fullUri () const; + QString userinfo () const; + bool hasHostname () const; + SchemeType schemeType () const; URI& operator=(const URI&); -- GitLab