diff --git a/src/account.cpp b/src/account.cpp index 47d6c73bd0e3edb75d137a8db7b9bf0aca3b5991..15f935fa83a31546e520f9295afe62f82f4e0fdb 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 6a5c998a2ce6c1ba658c035270fea902e7afc309..f23a355065d2223e57e4e628c2ae6d9a900ae743 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 4b59206c6739ba811cf9a1602d29dd01e906cee4..e37a1fdb54b29afff45e5a9e545f6cec9fc27592 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 2f4b20fc4e25a323b68e53d4e7c4fa0ec5981443..d71c56f3c1ba7d34b27bc94986852e8f473c7b37 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 543c99d1609cc9a4a09bd8c6c9ab5a728c558f96..b1eeaa24f5e1d57232453ca31f446d75e56f5d46 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 ca433c19c1ca320a1ff1c072cf3b9aa2836875ba..73f8f578c490f6d48499346a54ca99f294321c75 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 626ed06437ad53f5d43bbab42c4a87c09e2a9797..7611d2cd03f8be47061c78f8dc74966853ecbb52 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 397677682477c78f188657f200334c10dc1bf398..d9e0831492e0aec49784cec9d0876413b632fbcd 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 a58fa9b52abe21bc022794f30f37b22bb2a00c04..fb76009911146e3de3fbfda6aa0c0144a309dad5 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 943129e5158c2de11affc44d914a15d4da131f51..b745bd63a2d9be594e20db6f7fd23fccb932d463 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 d4119c7d223ac0bb842d6b2d6a074637407d6e38..f3353b4757805085b406784dd2a8d68a12810016 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&);