| /**************************************************************************** |
| * Copyright (C) 2009-2015 by Savoir-Faire Linux * |
| * 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 "account.h" |
| |
| //Qt |
| #include <QtCore/QDebug> |
| #include <QtCore/QObject> |
| #include <QtCore/QString> |
| |
| //Ring daemon |
| #include <account_const.h> |
| |
| //Ring lib |
| #include "dbus/configurationmanager.h" |
| #include "dbus/callmanager.h" |
| #include "dbus/videomanager.h" |
| #include "delegates/accountlistcolordelegate.h" |
| #include "certificate.h" |
| #include "certificatemodel.h" |
| #include "accountmodel.h" |
| #include "private/account_p.h" |
| #include "private/accountmodel_p.h" |
| #include "credentialmodel.h" |
| #include "ciphermodel.h" |
| #include "protocolmodel.h" |
| #include "bootstrapmodel.h" |
| #include "accountstatusmodel.h" |
| #include "codecmodel.h" |
| #include "ringtonemodel.h" |
| #include "contactmethod.h" |
| #include "phonedirectorymodel.h" |
| #include "presencestatusmodel.h" |
| #include "uri.h" |
| #include "securityevaluationmodel.h" |
| #include "private/securityevaluationmodel_p.h" |
| #define TO_BOOL ?"true":"false" |
| #define IS_TRUE == "true" |
| |
| #define AP &AccountPrivate |
| const account_function AccountPrivate::stateMachineActionsOnState[6][7] = { |
| /* NOTHING EDIT RELOAD SAVE REMOVE MODIFY CANCEL */ |
| /*READY */{ AP::nothing, AP::edit , AP::reload , AP::nothing, AP::remove , AP::modify , AP::nothing },/**/ |
| /*EDITING */{ AP::nothing, AP::nothing, AP::outdate, AP::nothing, AP::remove , AP::modify , AP::cancel },/**/ |
| /*OUTDATED */{ AP::nothing, AP::nothing, AP::nothing, AP::nothing, AP::remove , AP::reloadMod, AP::reload },/**/ |
| /*NEW */{ AP::nothing, AP::nothing, AP::nothing, AP::save , AP::remove , AP::nothing , AP::nothing },/**/ |
| /*MODIFIED */{ AP::nothing, AP::nothing, AP::nothing, AP::save , AP::remove , AP::nothing , AP::reload },/**/ |
| /*REMOVED */{ AP::nothing, AP::nothing, AP::nothing, AP::nothing, AP::nothing, AP::nothing , AP::cancel } /**/ |
| /* */ |
| }; |
| #undef AP |
| |
| AccountPrivate::AccountPrivate(Account* acc) : QObject(acc),q_ptr(acc),m_pCredentials(nullptr),m_pCodecModel(nullptr), |
| m_LastErrorCode(-1),m_VoiceMailCount(0),m_pRingToneModel(nullptr), |
| m_CurrentState(Account::EditState::READY), |
| m_pAccountNumber(nullptr),m_pKeyExchangeModel(nullptr),m_pSecurityEvaluationModel(nullptr),m_pTlsMethodModel(nullptr), |
| m_pCaCert(nullptr),m_pTlsCert(nullptr),m_pPrivateKey(nullptr),m_isLoaded(true),m_pCipherModel(nullptr), |
| m_pStatusModel(nullptr),m_LastTransportCode(0),m_RegistrationState(Account::RegistrationState::UNREGISTERED), |
| m_UseDefaultPort(false),m_pProtocolModel(nullptr),m_pBootstrapModel(nullptr),m_RemoteEnabledState(false) |
| { |
| Q_Q(Account); |
| } |
| |
| void AccountPrivate::changeState(Account::EditState state) { |
| Q_Q(Account); |
| m_CurrentState = state; |
| emit q_ptr->changed(q_ptr); |
| } |
| |
| ///Constructors |
| Account::Account():QObject(AccountModel::instance()),d_ptr(new AccountPrivate(this)) |
| { |
| } |
| |
| ///Build an account from it'id |
| Account* AccountPrivate::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 (AccountModel::instance()->d_ptr->m_hsPlaceHolder[_accountId]) { |
| AccountModel::instance()->d_ptr->m_hsPlaceHolder[_accountId]->d_ptr->merge(a); |
| } |
| |
| return a; |
| } //buildExistingAccountFromId |
| |
| ///Build an account from it's name / alias |
| Account* AccountPrivate::buildNewAccountFromAlias(Account::Protocol proto, const QString& alias) |
| { |
| qDebug() << "Building an account from alias: " << alias; |
| ConfigurationManagerInterface& configurationManager = DBus::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 = const_cast<ContactMethod*>(ContactMethod::BLANK()); |
| MapStringString tmp; |
| switch (proto) { |
| case Account::Protocol::SIP: |
| tmp = configurationManager.getAccountTemplate(DRing::Account::ProtocolNames::SIP); |
| break; |
| case Account::Protocol::IAX: |
| tmp = configurationManager.getAccountTemplate(DRing::Account::ProtocolNames::IAX); |
| break; |
| case Account::Protocol::RING: |
| tmp = configurationManager.getAccountTemplate(DRing::Account::ProtocolNames::RING); |
| break; |
| case Account::Protocol::COUNT__: |
| default: |
| break; |
| } |
| QMutableMapIterator<QString, QString> iter(tmp); |
| while (iter.hasNext()) { |
| iter.next(); |
| a->d_ptr->m_hAccountDetails[iter.key()] = iter.value(); |
| } |
| 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(); |
| if (d_ptr->m_pCredentials) delete d_ptr->m_pCredentials ; |
| if (d_ptr->m_pCodecModel) delete d_ptr->m_pCodecModel ; |
| } |
| |
| /***************************************************************************** |
| * * |
| * 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().toString()) |
| setAccountProperty(DRing::Account::ConfProperties::TLS::CA_LIST_FILE, cert->path().toString()); |
| break; |
| case Certificate::Type::USER: |
| if (accountDetail(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE) != cert->path().toString()) |
| setAccountProperty(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE, cert->path().toString()); |
| break; |
| case Certificate::Type::PRIVATE_KEY: |
| if (accountDetail(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE) != cert->path().toString()) |
| setAccountProperty(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE, cert->path().toString()); |
| 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(); |
| } |
| |
| ///Get this account ID |
| const QByteArray Account::id() const |
| { |
| if (isNew()) { |
| qDebug() << "Error : getting AccountId of a new account."; |
| } |
| if (d_ptr->m_AccountId.isEmpty()) { |
| qDebug() << "Account not configured"; |
| return QByteArray(); //WARNING May explode |
| } |
| |
| return d_ptr->m_AccountId; |
| } |
| |
| ///Get current state |
| const QString Account::toHumanStateName() const |
| { |
| const QString s = d_ptr->m_hAccountDetails[DRing::Account::ConfProperties::Registration::STATUS]; |
| |
| static const QString registered = tr("Registered" ); |
| static const QString notRegistered = tr("Not Registered" ); |
| static const QString trying = tr("Trying..." ); |
| static const QString error = tr("Error" ); |
| static const QString authenticationFailed = tr("Authentication Failed" ); |
| static const QString networkUnreachable = tr("Network unreachable" ); |
| static const QString hostUnreachable = tr("Host unreachable" ); |
| static const QString stunConfigurationError = tr("Stun configuration error" ); |
| static const QString stunServerInvalid = tr("Stun server invalid" ); |
| static const QString serviceUnavailable = tr("Service unavailable" ); |
| static const QString notAcceptable = tr("Unacceptable" ); |
| static const QString invalid = tr("Invalid" ); |
| static const QString requestTimeout = tr("Request Timeout" ); |
| |
| if(s == DRing::Account::States::REGISTERED ) |
| return registered ; |
| 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 |
| const 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; |
| } |
| if (q_ptr->protocol() != Account::Protocol::IAX) {//IAX accounts lack some fields, be quiet |
| 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 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(); |
| } |
| |
| ///Return status color name |
| QString Account::stateColorName() const |
| { |
| switch(registrationState()) { |
| case RegistrationState::READY: |
| return "darkGreen"; |
| case RegistrationState::UNREGISTERED: |
| return "black"; |
| case RegistrationState::TRYING: |
| return "orange"; |
| case RegistrationState::ERROR: |
| return "red"; |
| case RegistrationState::COUNT__: |
| break; |
| }; |
| return QString(); |
| } |
| |
| ///I |
| bool Account::isLoaded() const |
| { |
| return d_ptr->m_isLoaded; |
| } |
| |
| ///Return status Qt color, QColor is not part of QtCore, use using the global variant |
| QVariant Account::stateColor() const |
| { |
| return AccountListColorDelegate::instance()->getColor(this); |
| } |
| |
| ///Create and return the credential model |
| CredentialModel* Account::credentialModel() const |
| { |
| if (!d_ptr->m_pCredentials) { |
| d_ptr->m_pCredentials = new CredentialModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pCredentials; |
| } |
| |
| ///Create and return the audio codec model |
| CodecModel* Account::codecModel() const |
| { |
| if (!d_ptr->m_pCodecModel) { |
| d_ptr->m_pCodecModel = new CodecModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pCodecModel; |
| } |
| |
| RingToneModel* Account::ringToneModel() const |
| { |
| if (!d_ptr->m_pRingToneModel) |
| d_ptr->m_pRingToneModel = new RingToneModel(const_cast<Account*>(this)); |
| return d_ptr->m_pRingToneModel; |
| } |
| |
| KeyExchangeModel* Account::keyExchangeModel() const |
| { |
| if (!d_ptr->m_pKeyExchangeModel) { |
| d_ptr->m_pKeyExchangeModel = new KeyExchangeModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pKeyExchangeModel; |
| } |
| |
| CipherModel* Account::cipherModel() const |
| { |
| if (!d_ptr->m_pCipherModel) { |
| d_ptr->m_pCipherModel = new CipherModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pCipherModel; |
| } |
| |
| AccountStatusModel* Account::statusModel() const |
| { |
| if (!d_ptr->m_pStatusModel) { |
| d_ptr->m_pStatusModel = new AccountStatusModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pStatusModel; |
| } |
| |
| SecurityEvaluationModel* Account::securityValidationModel() const |
| { |
| if (!d_ptr->m_pSecurityEvaluationModel) { |
| d_ptr->m_pSecurityEvaluationModel = new SecurityEvaluationModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pSecurityEvaluationModel; |
| } |
| |
| TlsMethodModel* Account::tlsMethodModel() const |
| { |
| if (!d_ptr->m_pTlsMethodModel ) { |
| d_ptr->m_pTlsMethodModel = new TlsMethodModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pTlsMethodModel; |
| } |
| |
| ProtocolModel* Account::protocolModel() const |
| { |
| if (!d_ptr->m_pProtocolModel ) { |
| d_ptr->m_pProtocolModel = new ProtocolModel(const_cast<Account*>(this)); |
| } |
| return d_ptr->m_pProtocolModel; |
| } |
| |
| BootstrapModel* Account::bootstrapModel() const |
| { |
| if (protocol() != Account::Protocol::RING) |
| return nullptr; |
| |
| if (!d_ptr->m_pBootstrapModel ) { |
| d_ptr->m_pBootstrapModel = new BootstrapModel(const_cast<Account*>(this)); |
| } |
| |
| return d_ptr->m_pBootstrapModel; |
| } |
| |
| 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 the account user name |
| QString Account::username() const |
| { |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::USERNAME); |
| } |
| |
| ///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); |
| } |
| |
| |
| QString Account::password() const |
| { |
| switch (protocol()) { |
| case Account::Protocol::SIP: |
| if (credentialModel()->rowCount()) |
| return credentialModel()->data(credentialModel()->index(0,0),CredentialModel::Role::PASSWORD).toString(); |
| break; |
| case Account::Protocol::IAX: |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::PASSWORD); |
| break; |
| case Account::Protocol::RING: |
| return tlsPassword(); |
| break; |
| case Account::Protocol::COUNT__: |
| break; |
| }; |
| return ""; |
| } |
| |
| /// |
| bool Account::isDisplaySasOnce() const |
| { |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::ZRTP::DISPLAY_SAS_ONCE) IS_TRUE; |
| } |
| |
| ///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; |
| } |
| |
| /// |
| bool Account::isZrtpDisplaySas () const |
| { |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::ZRTP::DISPLAY_SAS) IS_TRUE; |
| } |
| |
| ///Return if the other side support warning |
| bool Account::isZrtpNotSuppWarning() const |
| { |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::ZRTP::NOT_SUPP_WARNING) IS_TRUE; |
| } |
| |
| /// |
| bool Account::isZrtpHelloHash() const |
| { |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::ZRTP::HELLO_HASH) 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()->getCertificate(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()->getCertificate(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 |
| Certificate* Account::tlsPrivateKeyCertificate() const |
| { |
| if (!d_ptr->m_pPrivateKey) { |
| const QString& path = d_ptr->accountDetail(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE); |
| if (path.isEmpty()) |
| return nullptr; |
| d_ptr->m_pPrivateKey = CertificateModel::instance()->getCertificate(path,Certificate::Type::PRIVATE_KEY); |
| connect(d_ptr->m_pPrivateKey,SIGNAL(changed()),d_ptr.data(),SLOT(slotUpdateCertificate())); |
| } |
| return d_ptr->m_pPrivateKey; |
| } |
| |
| ///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 the key exchange mechanism |
| KeyExchangeModel::Type Account::keyExchange() const |
| { |
| return KeyExchangeModel::fromDaemonName(d_ptr->accountDetail(DRing::Account::ConfProperties::SRTP::KEY_EXCHANGE)); |
| } |
| |
| ///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); |
| } |
| |
| ///Return the last error message received |
| QString Account::lastErrorMessage() const |
| { |
| return d_ptr->m_LastErrorMessage; |
| } |
| |
| ///Return the last error code (useful for debugging) |
| int Account::lastErrorCode() const |
| { |
| return d_ptr->m_LastErrorCode; |
| } |
| |
| ///Get the last transport error code, this is used to debug why registration failed |
| int Account::lastTransportErrorCode() const |
| { |
| return d_ptr->m_LastTransportCode; |
| } |
| |
| ///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: |
| case Account::Protocol::IAX: |
| 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 local interface |
| QString Account::localInterface() const |
| { |
| return d_ptr->accountDetail(DRing::Account::ConfProperties::LOCAL_INTERFACE); |
| } |
| |
| ///Return the account registration status |
| Account::RegistrationState Account::registrationState() const |
| { |
| return d_ptr->m_RegistrationState; |
| } |
| |
| ///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::IAX) |
| return Account::Protocol::IAX; |
| 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 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; |
| } |
| |
| bool Account::presenceStatus() const |
| { |
| return d_ptr->m_pAccountNumber->isPresent(); |
| } |
| |
| 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; |
| } |
| |
| #define CAST(item) static_cast<int>(item) |
| QVariant Account::roleData(int role) const |
| { |
| switch(role) { |
| //Generic |
| case Qt::DisplayRole: |
| case Qt::EditRole: |
| return alias(); |
| case Qt::CheckStateRole: |
| return QVariant(isEnabled() ? Qt::Checked : Qt::Unchecked); |
| case Qt::BackgroundRole: |
| return stateColor(); |
| case Qt::DecorationRole: |
| return AccountListColorDelegate::instance()->getIcon(this); |
| |
| //Specialized |
| case CAST(Account::Role::Alias): |
| return alias(); |
| case CAST(Account::Role::Proto): |
| return static_cast<int>(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().toLocalFile():QVariant(); |
| case CAST(Account::Role::TlsCertificate): |
| return tlsCertificate()?tlsCertificate()->path().toLocalFile():QVariant(); |
| case CAST(Account::Role::TlsPrivateKeyCertificate): |
| return tlsPrivateKeyCertificate()?tlsPrivateKeyCertificate()->path().toLocalFile():QVariant(); |
| 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::LocalInterface): |
| return localInterface(); |
| 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::DisplaySasOnce): |
| return isDisplaySasOnce(); |
| case CAST(Account::Role::SrtpRtpFallback): |
| return isSrtpRtpFallback(); |
| case CAST(Account::Role::ZrtpDisplaySas): |
| return isZrtpDisplaySas(); |
| case CAST(Account::Role::ZrtpNotSuppWarning): |
| return isZrtpNotSuppWarning(); |
| case CAST(Account::Role::ZrtpHelloHash): |
| return isZrtpHelloHash(); |
| 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(Account::Role::Object): { |
| QVariant var; |
| var.setValue(const_cast<Account*>(this)); |
| return var; |
| } |
| case CAST(Account::Role::TypeName): |
| return static_cast<int>(protocol()); |
| case CAST(Account::Role::PresenceStatus): |
| return PresenceStatusModel::instance()->currentStatus(); |
| case CAST(Account::Role::PresenceMessage): |
| return PresenceStatusModel::instance()->currentMessage(); |
| case CAST(Account::Role::RegistrationState): |
| return QVariant::fromValue(registrationState()); |
| default: |
| return QVariant(); |
| } |
| } |
| #undef CAST |
| |
| |
| bool Account::supportScheme( URI::SchemeType type ) |
| { |
| switch(type) { |
| case URI::SchemeType::NONE : |
| if (protocol() == Account::Protocol::RING) |
| return false; |
| return true; |
| break; |
| case URI::SchemeType::SIP : |
| case URI::SchemeType::SIPS : |
| if (protocol() == Account::Protocol::SIP) |
| return true; |
| break; |
| case URI::SchemeType::IAX : |
| case URI::SchemeType::IAX2 : |
| if (protocol() == Account::Protocol::IAX) |
| return true; |
| break; |
| case URI::SchemeType::RING : |
| if (protocol() == Account::Protocol::RING) |
| return true; |
| break; |
| } |
| return false; |
| } |
| |
| |
| /***************************************************************************** |
| * * |
| * 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) { |
| q_ptr->performAction(Account::EditAction::MODIFY); |
| if (m_CurrentState == Account::EditState::MODIFIED || m_CurrentState == Account::EditState::NEW) { |
| m_hAccountDetails[param] = val; |
| emit q_ptr->changed(q_ptr); |
| emit q_ptr->propertyChanged(q_ptr,param,val,buf); |
| } |
| } |
| return m_CurrentState == Account::EditState::MODIFIED || m_CurrentState == Account::EditState::NEW; |
| } |
| |
| ///Set the account id |
| void Account::setId(const QByteArray& id) |
| { |
| qDebug() << "Setting accountId = " << d_ptr->m_AccountId; |
| if (! isNew()) |
| qDebug() << "Error : setting AccountId of an existing account."; |
| d_ptr->m_AccountId = id; |
| } |
| |
| ///Set the account type, SIP or IAX |
| 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::IAX: |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::TYPE ,DRing::Account::ProtocolNames::IAX ); |
| 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 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); |
| } |
| |
| ///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 main credential password |
| void Account::setPassword(const QString& detail) |
| { |
| switch (protocol()) { |
| case Account::Protocol::SIP: |
| if (credentialModel()->rowCount()) |
| credentialModel()->setData(credentialModel()->index(0,0),detail,CredentialModel::Role::PASSWORD); |
| else { |
| const QModelIndex idx = credentialModel()->addCredentials(); |
| credentialModel()->setData(idx,detail,CredentialModel::Role::PASSWORD); |
| } |
| break; |
| case Account::Protocol::IAX: |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::PASSWORD, detail); |
| break; |
| case Account::Protocol::RING: |
| setTlsPassword(detail); |
| case Account::Protocol::COUNT__: |
| break; |
| }; |
| } |
| |
| ///Set the TLS (encryption) password |
| void Account::setTlsPassword(const QString& 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()->getCertificate(path); |
| setTlsCaListCertificate(cert); |
| } |
| |
| ///Set the certificate |
| void Account::setTlsCertificate(const QString& path) |
| { |
| Certificate* cert = CertificateModel::instance()->getCertificate(path); |
| setTlsCertificate(cert); |
| } |
| |
| ///Set the private key |
| void Account::setTlsPrivateKeyCertificate(const QString& path) |
| { |
| Certificate* cert = CertificateModel::instance()->getCertificate(path); |
| setTlsPrivateKeyCertificate(cert); |
| } |
| |
| ///Set the certificate authority list file |
| void Account::setTlsCaListCertificate(Certificate* cert) |
| { |
| d_ptr->m_pCaCert = cert; |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::CA_LIST_FILE, cert?cert->path().path():QString()); |
| d_ptr->regenSecurityValidation(); |
| } |
| |
| ///Set the certificate |
| void Account::setTlsCertificate(Certificate* cert) |
| { |
| d_ptr->m_pTlsCert = cert; |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::CERTIFICATE_FILE, cert?cert->path().path():QString()); |
| d_ptr->regenSecurityValidation(); |
| } |
| |
| ///Set the private key |
| void Account::setTlsPrivateKeyCertificate(Certificate* cert) |
| { |
| d_ptr->m_pPrivateKey = cert; |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::TLS::PRIVATE_KEY_FILE, cert?cert->path().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 local interface |
| void Account::setLocalInterface(const QString& detail) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::LOCAL_INTERFACE, 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 last error message to be displayed as status instead of "Error" |
| void Account::setLastErrorMessage(const QString& message) |
| { |
| d_ptr->m_LastErrorMessage = message; |
| } |
| |
| ///Set the last error code |
| void Account::setLastErrorCode(int code) |
| { |
| d_ptr->m_LastErrorCode = code; |
| } |
| |
| ///Set the Tls method |
| void Account::setKeyExchange(KeyExchangeModel::Type detail) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::SRTP::KEY_EXCHANGE ,KeyExchangeModel::toDaemonName(detail)); |
| d_ptr->regenSecurityValidation(); |
| } |
| |
| ///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/IAX communications |
| void Account::setLocalPort(unsigned short detail) |
| { |
| switch (protocol()) { |
| case Account::Protocol::SIP: |
| case Account::Protocol::IAX: |
| 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)); |
| 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::setDisplaySasOnce(bool detail) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::ZRTP::DISPLAY_SAS_ONCE, (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::setZrtpDisplaySas(bool detail) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::ZRTP::DISPLAY_SAS, (detail)TO_BOOL); |
| d_ptr->regenSecurityValidation(); |
| } |
| |
| void Account::setZrtpNotSuppWarning(bool detail) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::ZRTP::NOT_SUPP_WARNING, (detail)TO_BOOL); |
| d_ptr->regenSecurityValidation(); |
| } |
| |
| void Account::setZrtpHelloHash(bool detail) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::ZRTP::HELLO_HASH, (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: |
| case Account::Protocol::IAX: |
| setLocalPort(5060); |
| break; |
| case Account::Protocol::RING: |
| setLocalPort(5061); |
| break; |
| case Account::Protocol::COUNT__: |
| break; |
| }; |
| } |
| d_ptr->m_UseDefaultPort = value; |
| } |
| |
| ///Set the DTMF type |
| void Account::setDTMFType(DtmfType type) |
| { |
| d_ptr->setAccountProperty(DRing::Account::ConfProperties::DTMF_TYPE,(type==OverRtp)?"overrtp":"oversip"); |
| } |
| |
| #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): { |
| const QString path = value.toString(); |
| if ((tlsCaListCertificate() && tlsCaListCertificate()->path() != QUrl(path)) || !tlsCaListCertificate()) { |
| tlsCaListCertificate()->setPath(path); |
| } |
| break; |
| } |
| case CAST(Account::Role::TlsCertificate): { |
| const QString path = value.toString(); |
| if ((tlsCertificate() && tlsCertificate()->path() != QUrl(path)) || !tlsCertificate()) |
| tlsCertificate()->setPath(path); |
| } |
| break; |
| case CAST(Account::Role::TlsPrivateKeyCertificate): { |
| const QString path = value.toString(); |
| if ((tlsPrivateKeyCertificate() && tlsPrivateKeyCertificate()->path() != QUrl(path)) || !tlsPrivateKeyCertificate()) |
| tlsPrivateKeyCertificate()->setPath(path); |
| } |
| 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::LocalInterface): |
| setLocalInterface(value.toString()); |
| break; |
| case CAST(Account::Role::RingtonePath): |
| setRingtonePath(value.toString()); |
| break; |
| case CAST(Account::Role::KeyExchange): { |
| const int method = value.toInt(); |
| setKeyExchange(method<=keyExchangeModel()->rowCount()?static_cast<KeyExchangeModel::Type>(method):KeyExchangeModel::Type::NONE); |
| 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::DisplaySasOnce): |
| setDisplaySasOnce(value.toBool()); |
| break; |
| case CAST(Account::Role::SrtpRtpFallback): |
| setSrtpRtpFallback(value.toBool()); |
| break; |
| case CAST(Account::Role::ZrtpDisplaySas): |
| setZrtpDisplaySas(value.toBool()); |
| break; |
| case CAST(Account::Role::ZrtpNotSuppWarning): |
| setZrtpNotSuppWarning(value.toBool()); |
| break; |
| case CAST(Account::Role::ZrtpHelloHash): |
| setZrtpHelloHash(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; |
| } |
| } |
| #undef CAST |
| |
| |
| /***************************************************************************** |
| * * |
| * Mutator * |
| * * |
| ****************************************************************************/ |
| |
| void AccountPrivate::performAction(const Account::EditAction action) |
| { |
| (this->*(stateMachineActionsOnState[(int)m_CurrentState][(int)action]))();//FIXME don't use integer cast |
| } |
| |
| /// 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; |
| } |
| |
| /**Update the account |
| * @return if the state changed |
| */ |
| bool AccountPrivate::updateState() |
| { |
| if(! q_ptr->isNew()) { |
| ConfigurationManagerInterface& configurationManager = DBus::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 = AccountModelPrivate::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; |
| } |
| |
| ///Save the current account to the daemon |
| void AccountPrivate::save() |
| { |
| ConfigurationManagerInterface& configurationManager = DBus::ConfigurationManager::instance(); |
| if (q_ptr->isNew()) { |
| MapStringString details; |
| QMutableHashIterator<QString,QString> iter(m_hAccountDetails); |
| |
| while (iter.hasNext()) { |
| iter.next(); |
| details[iter.key()] = iter.value(); |
| } |
| |
| const QString currentId = configurationManager.addAccount(details); |
| |
| //Be sure there is audio codec enabled to avoid obscure error messages for the user |
| const QVector<uint> codecIdList = configurationManager.getCodecList(); |
| foreach (const int aCodec, codecIdList) { |
| const QMap<QString,QString> codec = configurationManager.getCodecDetails(q_ptr->id(),aCodec); |
| const QModelIndex idx = q_ptr->codecModel()->add(); |
| /*Ring::Account::ConfProperties::CodecInfo::NAME ; //TODO move this to CodecModel |
| Ring::Account::ConfProperties::CodecInfo::TYPE ; |
| Ring::Account::ConfProperties::CodecInfo::SAMPLE_RATE ; |
| Ring::Account::ConfProperties::CodecInfo::FRAME_RATE ; |
| Ring::Account::ConfProperties::CodecInfo::BITRATE ; |
| Ring::Account::ConfProperties::CodecInfo::CHANNEL_NUMBER;*/ |
| m_pCodecModel->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::NAME ] ,CodecModel::Role::NAME ); |
| m_pCodecModel->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::SAMPLE_RATE ] ,CodecModel::Role::SAMPLERATE ); |
| m_pCodecModel->setData(idx,codec[ DRing::Account::ConfProperties::CodecInfo::BITRATE ] ,CodecModel::Role::BITRATE ); |
| m_pCodecModel->setData(idx,QString::number(aCodec) ,CodecModel::Role::ID ); |
| m_pCodecModel->setData(idx, Qt::Checked ,Qt::CheckStateRole); |
| } |
| q_ptr->codecModel()->save(); |
| |
| 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); |
| } |
| } |
| |
| //Save the credentials if they changed |
| q_ptr->credentialModel() << CredentialModel::EditAction::SAVE; |
| |
| if (!q_ptr->id().isEmpty()) { |
| Account* acc = AccountModel::instance()->getById(q_ptr->id()); |
| qDebug() << "Adding the new account to the account list (" << q_ptr->id() << ")"; |
| if (acc != q_ptr) { |
| AccountModel::instance()->add(q_ptr); |
| } |
| |
| q_ptr->performAction(Account::EditAction::RELOAD); |
| updateState(); |
| m_CurrentState = Account::EditState::READY; |
| } |
| |
| q_ptr->codecModel()->save(); |
| |
| 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 = DBus::ConfigurationManager::instance(); |
| QMap<QString,QString> aDetails = configurationManager.getAccountDetails(q_ptr->id()); |
| |
| if (!aDetails.count()) { |
| qDebug() << "Account not found"; |
| } |
| else { |
| m_hAccountDetails.clear(); |
| QMutableMapIterator<QString, QString> iter(aDetails); |
| while (iter.hasNext()) { |
| iter.next(); |
| m_hAccountDetails[iter.key()] = iter.value(); |
| } |
| q_ptr->setHostname(m_hAccountDetails[DRing::Account::ConfProperties::HOSTNAME]); |
| m_RemoteEnabledState = q_ptr->isEnabled(); |
| } |
| m_CurrentState = 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))); |
| } |
| |
| //If the credential model is loaded, then update it |
| if (m_pCredentials) |
| m_pCredentials << CredentialModel::EditAction::RELOAD; |
| 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() { |
| changeState(Account::EditState::MODIFIED); |
| } |
| |
| 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->m_AccountId = uid ; |
| d_ptr->m_isLoaded = false; |
| } |
| |
| ///Merge an existing account into this temporary one |
| bool AccountPrivate::merge(Account* account) |
| { |
| if ((!account) || this == account->d_ptr.data()) |
| return false; |
| |
| AccountPrivate* p = (AccountPrivate*) d_ptr.take(); |
| delete p; |
| |
| q_ptr->d_ptr = account->d_ptr; |
| emit q_ptr->changed(q_ptr); |
| |
| return true; |
| } |
| |
| #undef TO_BOOL |
| #undef IS_TRUE |
| #include <account.moc> |