/* * Copyright (c) 2010-2024 Belledonne Communications SARL. * * This file is part of linphone-desktop * (see https://www.linphone.org). * * 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 . */ #include "AccountModel.hpp" #include "core/path/Paths.hpp" #include "model/core/CoreModel.hpp" #include "tool/Utils.hpp" #include "tool/providers/AvatarProvider.hpp" #include #include DEFINE_ABSTRACT_OBJECT(AccountModel) AccountModel::AccountModel(const std::shared_ptr &account, QObject *parent) : ::Listener(account, parent) { mustBeInLinphoneThread(getClassName()); connect(CoreModel::getInstance().get(), &CoreModel::defaultAccountChanged, this, &AccountModel::onDefaultAccountChanged); // Hack because Account doesn't provide callbacks on updated data connect(this, &AccountModel::defaultAccountChanged, this, [this]() { emit pictureUriChanged(Utils::coreStringToAppString(mMonitor->getParams()->getPictureUri())); emit displayNameChanged( Utils::coreStringToAppString(mMonitor->getParams()->getIdentityAddress()->getDisplayName())); }); connect(CoreModel::getInstance().get(), &CoreModel::unreadNotificationsChanged, this, [this]() { emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/, mMonitor->getMissedCallsCount()); // TODO }); } AccountModel::~AccountModel() { mustBeInLinphoneThread("~" + getClassName()); } void AccountModel::onRegistrationStateChanged(const std::shared_ptr &account, linphone::RegistrationState state, const std::string &message) { emit registrationStateChanged(account, state, message); } void AccountModel::onMessageWaitingIndicationChanged( const std::shared_ptr &account, const std::shared_ptr &mwi) { auto userData = getUserData(account); if (!userData) userData = std::make_shared(); userData->showMwi = mwi->hasMessageWaiting(); for (auto summary : mwi->getSummaries()) { qInfo() << "[MWI] new" << summary->getNbNew() << "new+urgent" << summary->getNbNewUrgent() << "old" << summary->getNbOld() << "old+urgent" << summary->getNbOldUrgent(); userData->voicemailCount = summary->getNbNew(); emit voicemailCountChanged(summary->getNbNew()); } setUserData(account, userData); emit showMwiChanged(mwi->hasMessageWaiting()); } void AccountModel::setPictureUri(QString uri) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto oldPictureUri = Utils::coreStringToAppString(params->getPictureUri()); if (!oldPictureUri.isEmpty()) { QString appPrefix = QStringLiteral("image://%1/").arg(AvatarProvider::ProviderId); if (oldPictureUri.startsWith(appPrefix)) { oldPictureUri = Paths::getAvatarsDirPath() + oldPictureUri.mid(appPrefix.length()); } QFile oldPicture(oldPictureUri); if (!oldPicture.remove()) qWarning() << log().arg("Cannot delete old avatar file at " + oldPictureUri); } params->setPictureUri(Utils::appStringToCoreString(uri)); mMonitor->setParams(params); // Hack because Account doesn't provide callbacks on updated data // emit pictureUriChanged(uri); auto core = CoreModel::getInstance()->getCore(); emit CoreModel::getInstance()->defaultAccountChanged(core, core->getDefaultAccount()); } void AccountModel::onDefaultAccountChanged() { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); emit defaultAccountChanged(CoreModel::getInstance()->getCore()->getDefaultAccount() == mMonitor); } void AccountModel::setDefault() { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto core = CoreModel::getInstance()->getCore(); core->setDefaultAccount(mMonitor); } void AccountModel::removeAccount() { CoreModel::getInstance()->getCore()->removeAccount(mMonitor); removeUserData(mMonitor); emit removed(); } void AccountModel::resetMissedCallsCount() { mMonitor->resetMissedCallsCount(); emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/, mMonitor->getMissedCallsCount()); // TODO } void AccountModel::refreshUnreadNotifications() { emit unreadNotificationsChanged(0 /*mMonitor->getUnreadChatMessageCount()*/, mMonitor->getMissedCallsCount()); // TODO } int AccountModel::getMissedCallsCount() const { return mMonitor->getMissedCallsCount(); } int AccountModel::getUnreadMessagesCount() const { return mMonitor->getUnreadChatMessageCount(); } void AccountModel::setDisplayName(QString displayName) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto address = params->getIdentityAddress()->clone(); address->setDisplayName(Utils::appStringToCoreString(displayName)); params->setIdentityAddress(address); mMonitor->setParams(params); // Hack because Account doesn't provide callbacks on updated data // emit displayNameChanged(displayName); auto core = CoreModel::getInstance()->getCore(); emit CoreModel::getInstance()->defaultAccountChanged(core, core->getDefaultAccount()); } void AccountModel::setDialPlan(int index) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); std::string callingCode = ""; std::string countryCode = ""; if (index != -1) { auto plans = linphone::Factory::get()->getDialPlans(); std::vector> vectorPlans(plans.begin(), plans.end()); auto plan = vectorPlans[index]; callingCode = plan->getCountryCallingCode(); countryCode = plan->getIsoCountryCode(); } auto params = mMonitor->getParams()->clone(); params->setInternationalPrefix(callingCode); params->setInternationalPrefixIsoCountryCode(countryCode); mMonitor->setParams(params); emit dialPlanChanged(index); } void AccountModel::setRegisterEnabled(bool enabled) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->enableRegister(enabled); mMonitor->setParams(params); emit registerEnabledChanged(enabled); } std::string AccountModel::getConfigAccountUiSection() { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); return "ui_" + mMonitor->getParams()->getIdentityAddress()->asStringUriOnly(); } bool AccountModel::getNotificationsAllowed() { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); return mMonitor->getCore()->getConfig()->getBool(getConfigAccountUiSection(), "notifications_allowed", true); } void AccountModel::setNotificationsAllowed(bool value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); mMonitor->getCore()->getConfig()->setBool(getConfigAccountUiSection(), "notifications_allowed", value); emit notificationsAllowedChanged(value); } void AccountModel::setMwiServerAddress(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto address = value.isEmpty() ? nullptr : CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(value), false); if (value.isEmpty() || address) { params->setMwiServerAddress(address); mMonitor->setParams(params); emit mwiServerAddressChanged(value); } else qWarning() << "Unable to set MWI address, failed creating address from" << value; } void AccountModel::setTransport(linphone::TransportType value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->setTransport(value); mMonitor->setParams(params); emit transportChanged(value); } void AccountModel::setServerAddress(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto address = CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(value), false); if (address) { params->setServerAddress(address); mMonitor->setParams(params); emit serverAddressChanged(value); } else qWarning() << "Unable to set ServerAddress, failed creating address from" << value; } void AccountModel::setOutboundProxyEnabled(bool value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->enableOutboundProxy(value); mMonitor->setParams(params); emit outboundProxyEnabledChanged(value); } void AccountModel::setStunServer(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto policy = params->getNatPolicy(); if (!policy) policy = mMonitor->getCore()->createNatPolicy(); policy->setStunServer(Utils::appStringToCoreString(value)); policy->enableStun(!value.isEmpty()); params->setNatPolicy(policy); mMonitor->setParams(params); emit stunServerChanged(value); } void AccountModel::setIceEnabled(bool value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto policy = params->getNatPolicy(); if (!policy) policy = mMonitor->getCore()->createNatPolicy(); policy->enableIce(value); params->setNatPolicy(policy); mMonitor->setParams(params); emit iceEnabledChanged(value); } void AccountModel::setAvpfEnabled(bool value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->setAvpfMode(value ? linphone::AVPFMode::Enabled : linphone::AVPFMode::Disabled); mMonitor->setParams(params); emit avpfEnabledChanged(value); } void AccountModel::setBundleModeEnabled(bool value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->enableRtpBundle(value); mMonitor->setParams(params); emit bundleModeEnabledChanged(value); } void AccountModel::setExpire(int value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->setExpires(value); mMonitor->setParams(params); emit expireChanged(value); } void AccountModel::setConferenceFactoryAddress(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto address = value.isEmpty() ? nullptr : CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(value), false); if (value.isEmpty() || address) { params->setConferenceFactoryAddress(address); mMonitor->setParams(params); emit conferenceFactoryAddressChanged(value); } else qWarning() << "Unable to set ConferenceFactoryAddress address, failed creating address from" << value; } void AccountModel::setAudioVideoConferenceFactoryAddress(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto address = value.isEmpty() ? nullptr : CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(value), false); if (value.isEmpty() || address) { params->setAudioVideoConferenceFactoryAddress(address); mMonitor->setParams(params); emit audioVideoConferenceFactoryAddressChanged(value); } else qWarning() << "Unable to set AudioVideoConferenceFactoryAddress address, failed creating address from" << value; } void AccountModel::setLimeServerUrl(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); params->setLimeServerUrl(Utils::appStringToCoreString(value)); mMonitor->setParams(params); emit limeServerUrlChanged(value); } QString AccountModel::dialPlanAsString(const std::shared_ptr &dialPlan) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); return Utils::coreStringToAppString(dialPlan->getFlag() + " " + dialPlan->getCountry() + " | +" + dialPlan->getCountryCallingCode()); } int AccountModel::getVoicemailCount() { auto userData = getUserData(mMonitor); if (userData) return userData->voicemailCount; else return 0; } bool AccountModel::getShowMwi() { auto userData = getUserData(mMonitor); if (userData) return userData->showMwi; else return false; } void AccountModel::setVoicemailAddress(QString value) { mustBeInLinphoneThread(log().arg(Q_FUNC_INFO)); auto params = mMonitor->getParams()->clone(); auto address = value.isEmpty() ? nullptr : CoreModel::getInstance()->getCore()->interpretUrl(Utils::appStringToCoreString(value), false); if (value.isEmpty() || address) { params->setVoicemailAddress(address); mMonitor->setParams(params); emit voicemailAddressChanged(value); } else qWarning() << "Unable to set VoicemailAddress, failed creating address from" << value; } // UserData (see hpp for explanations) static QMap, std::shared_ptr> userDataMap; void AccountModel::setUserData(const std::shared_ptr &account, std::shared_ptr &data) { mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); userDataMap[account] = data; } std::shared_ptr AccountModel::getUserData(const std::shared_ptr &account) { mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); if (userDataMap.contains(account)) return userDataMap.value(account); else return nullptr; } void AccountModel::removeUserData(const std::shared_ptr &account) { mustBeInLinphoneThread(sLog().arg(Q_FUNC_INFO)); userDataMap.remove(account); }