LCOV - code coverage report
Current view: top level - foo/src/client - configurationmanager.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 55 557 9.9 %
Date: 2025-12-18 10:07:43 Functions: 15 142 10.6 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2025 Savoir-faire Linux Inc.
       3             :  *
       4             :  *  This program is free software: you can redistribute it and/or modify
       5             :  *  it under the terms of the GNU General Public License as published by
       6             :  *  the Free Software Foundation, either version 3 of the License, or
       7             :  *  (at your option) any later version.
       8             :  *
       9             :  *  This program is distributed in the hope that it will be useful,
      10             :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
      12             :  *  GNU General Public License for more details.
      13             :  *
      14             :  *  You should have received a copy of the GNU General Public License
      15             :  *  along with this program. If not, see <https://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #ifdef HAVE_CONFIG_H
      19             : #include "config.h"
      20             : #endif
      21             : 
      22             : #include "configurationmanager_interface.h"
      23             : #include "account_schema.h"
      24             : #include "manager.h"
      25             : #include "logger.h"
      26             : #include "fileutils.h"
      27             : #include "archiver.h"
      28             : #include "sip/sipaccount.h"
      29             : #include "jamidht/jamiaccount.h"
      30             : #include "sip/sipaccount_config.h"
      31             : #include "jamidht/jamiaccount_config.h"
      32             : #include "audio/audiolayer.h"
      33             : #include "system_codec_container.h"
      34             : #include "account_const.h"
      35             : #include "client/ring_signal.h"
      36             : #include "audio/ringbufferpool.h"
      37             : #include "connectivity/security/tlsvalidator.h"
      38             : 
      39             : #include <dhtnet/ip_utils.h>
      40             : #include <dhtnet/upnp/upnp_context.h>
      41             : #include <dhtnet/certstore.h>
      42             : 
      43             : #include <regex>
      44             : 
      45             : #ifdef __APPLE__
      46             : #include <TargetConditionals.h>
      47             : #endif
      48             : 
      49             : #ifdef _MSC_VER
      50             : #include "windirent.h"
      51             : #else
      52             : #include <dirent.h>
      53             : #endif
      54             : 
      55             : #include <cerrno>
      56             : #include <cstring>
      57             : #include <sstream>
      58             : 
      59             : #ifdef _WIN32
      60             : #undef interface
      61             : #endif
      62             : 
      63             : #include <string_view>
      64             : 
      65             : namespace libjami {
      66             : 
      67             : constexpr unsigned CODECS_NOT_LOADED = 0x1000; /** Codecs not found */
      68             : 
      69             : using jami::SIPAccount;
      70             : using jami::JamiAccount;
      71             : using jami::tls::TlsValidator;
      72             : using jami::AudioDeviceType;
      73             : 
      74             : void
      75           0 : registerConfHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>& handlers)
      76             : {
      77           0 :     registerSignalHandlers(handlers);
      78           0 : }
      79             : 
      80             : std::map<std::string, std::string>
      81           0 : getAccountDetails(const std::string& accountId)
      82             : {
      83           0 :     return jami::Manager::instance().getAccountDetails(accountId);
      84             : }
      85             : 
      86             : std::map<std::string, std::string>
      87           0 : getVolatileAccountDetails(const std::string& accountId)
      88             : {
      89           0 :     return jami::Manager::instance().getVolatileAccountDetails(accountId);
      90             : }
      91             : 
      92             : std::map<std::string, std::string>
      93           0 : validateCertificate(const std::string& accountId, const std::string& certificate)
      94             : {
      95             :     try {
      96           0 :         if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
      97           0 :             return TlsValidator {acc->certStore(), acc->certStore().getCertificate(certificate)}.getSerializedChecks();
      98           0 :     } catch (const std::runtime_error& e) {
      99           0 :         JAMI_WARN("Certificate loading failed: %s", e.what());
     100           0 :     }
     101           0 :     return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
     102             : }
     103             : 
     104             : std::map<std::string, std::string>
     105           0 : validateCertificatePath(const std::string& accountId,
     106             :                         const std::string& certificate,
     107             :                         const std::string& privateKey,
     108             :                         const std::string& privateKeyPass,
     109             :                         const std::string& caList)
     110             : {
     111             :     try {
     112           0 :         if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     113           0 :             return TlsValidator {acc->certStore(), certificate, privateKey, privateKeyPass, caList}.getSerializedChecks();
     114           0 :     } catch (const std::runtime_error& e) {
     115           0 :         JAMI_WARN("Certificate loading failed: %s", e.what());
     116           0 :         return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
     117           0 :     }
     118           0 :     return {};
     119             : }
     120             : 
     121             : std::map<std::string, std::string>
     122           0 : getCertificateDetails(const std::string& accountId, const std::string& certificate)
     123             : {
     124             :     try {
     125           0 :         if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     126           0 :             return TlsValidator {acc->certStore(), acc->certStore().getCertificate(certificate)}.getSerializedDetails();
     127           0 :     } catch (const std::runtime_error& e) {
     128           0 :         JAMI_WARN("Certificate loading failed: %s", e.what());
     129           0 :     }
     130           0 :     return {};
     131             : }
     132             : 
     133             : std::map<std::string, std::string>
     134           0 : getCertificateDetailsPath(const std::string& accountId,
     135             :                           const std::string& certificate,
     136             :                           const std::string& privateKey,
     137             :                           const std::string& privateKeyPassword)
     138             : {
     139             :     try {
     140           0 :         auto crt = std::make_shared<dht::crypto::Certificate>(jami::fileutils::loadFile(certificate));
     141           0 :         if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     142           0 :             TlsValidator validator {acc->certStore(), certificate, privateKey, privateKeyPassword};
     143           0 :             acc->certStore().pinCertificate(validator.getCertificate(), false);
     144           0 :             return validator.getSerializedDetails();
     145           0 :         }
     146           0 :     } catch (const std::runtime_error& e) {
     147           0 :         JAMI_WARN("Certificate loading failed: %s", e.what());
     148           0 :     }
     149           0 :     return {};
     150             : }
     151             : 
     152             : std::vector<std::string>
     153           0 : getPinnedCertificates(const std::string& accountId)
     154             : {
     155           0 :     if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     156           0 :         return acc->certStore().getPinnedCertificates();
     157           0 :     return {};
     158             : }
     159             : 
     160             : std::vector<std::string>
     161           0 : pinCertificate(const std::string& accountId, const std::vector<uint8_t>& certificate, bool local)
     162             : {
     163           0 :     if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     164           0 :         return acc->certStore().pinCertificate(certificate, local);
     165           0 :     return {};
     166             : }
     167             : 
     168             : void
     169           0 : pinCertificatePath(const std::string& accountId, const std::string& path)
     170             : {
     171           0 :     if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     172           0 :         acc->certStore().pinCertificatePath(path);
     173           0 : }
     174             : 
     175             : bool
     176           0 : unpinCertificate(const std::string& accountId, const std::string& certId)
     177             : {
     178           0 :     if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     179           0 :         return acc->certStore().unpinCertificate(certId);
     180           0 :     return {};
     181             : }
     182             : 
     183             : unsigned
     184           0 : unpinCertificatePath(const std::string& accountId, const std::string& path)
     185             : {
     186           0 :     if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     187           0 :         return acc->certStore().unpinCertificatePath(path);
     188           0 :     return {};
     189             : }
     190             : 
     191             : bool
     192           0 : pinRemoteCertificate(const std::string& accountId, const std::string& certId)
     193             : {
     194           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     195           0 :         acc->dht()->findCertificate(dht::InfoHash(certId), [](const std::shared_ptr<dht::crypto::Certificate>& crt) {});
     196           0 :         return true;
     197           0 :     }
     198           0 :     return false;
     199             : }
     200             : 
     201             : bool
     202           0 : setCertificateStatus(const std::string& accountId, const std::string& certId, const std::string& ststr)
     203             : {
     204             :     try {
     205           0 :         if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     206           0 :             auto status = dhtnet::tls::TrustStore::statusFromStr(ststr.c_str());
     207           0 :             return acc->setCertificateStatus(certId, status);
     208           0 :         }
     209           0 :     } catch (const std::out_of_range&) {
     210           0 :     }
     211           0 :     return false;
     212             : }
     213             : 
     214             : std::vector<std::string>
     215           0 : getCertificatesByStatus(const std::string& accountId, const std::string& ststr)
     216             : {
     217           0 :     auto status = dhtnet::tls::TrustStore::statusFromStr(ststr.c_str());
     218           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     219           0 :         return acc->getCertificatesByStatus(status);
     220           0 :     return {};
     221             : }
     222             : 
     223             : void
     224          16 : setAccountDetails(const std::string& accountId, const std::map<std::string, std::string>& details)
     225             : {
     226          16 :     jami::Manager::instance().setAccountDetails(accountId, details);
     227          16 : }
     228             : 
     229             : void
     230           0 : setAccountActive(const std::string& accountId, bool enable, bool shutdownConnections)
     231             : {
     232           0 :     jami::Manager::instance().setAccountActive(accountId, enable, shutdownConnections);
     233           0 : }
     234             : 
     235             : void
     236           0 : loadAccountAndConversation(const std::string& accountId, bool loadAll, const std::string& convId)
     237             : {
     238           0 :     jami::Manager::instance().loadAccountAndConversation(accountId, loadAll, convId);
     239           0 : }
     240             : 
     241             : void
     242           0 : sendRegister(const std::string& accountId, bool enable)
     243             : {
     244           0 :     jami::Manager::instance().sendRegister(accountId, enable);
     245           0 : }
     246             : 
     247             : bool
     248           0 : isPasswordValid(const std::string& accountId, const std::string& password)
     249             : {
     250           0 :     if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(accountId))
     251           0 :         return acc->isPasswordValid(password);
     252           0 :     return false;
     253             : }
     254             : 
     255             : std::vector<uint8_t>
     256           0 : getPasswordKey(const std::string& accountID, const std::string& password)
     257             : {
     258           0 :     if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(accountID))
     259           0 :         return acc->getPasswordKey(password);
     260           0 :     return {};
     261             : }
     262             : 
     263             : void
     264           0 : registerAllAccounts()
     265             : {
     266           0 :     jami::Manager::instance().registerAccounts();
     267           0 : }
     268             : 
     269             : uint64_t
     270           0 : sendAccountTextMessage(const std::string& accountId,
     271             :                        const std::string& to,
     272             :                        const std::map<std::string, std::string>& payloads,
     273             :                        int32_t flags)
     274             : {
     275           0 :     bool onlyConnected = flags & 0x1;
     276           0 :     return jami::Manager::instance().sendTextMessage(accountId, to, payloads, onlyConnected);
     277             : }
     278             : 
     279             : std::vector<Message>
     280           0 : getLastMessages(const std::string& accountId, const uint64_t& base_timestamp)
     281             : {
     282           0 :     if (const auto acc = jami::Manager::instance().getAccount(accountId))
     283           0 :         return acc->getLastMessages(base_timestamp);
     284           0 :     return {};
     285             : }
     286             : 
     287             : std::map<std::string, std::string>
     288           0 : getNearbyPeers(const std::string& accountId)
     289             : {
     290           0 :     return jami::Manager::instance().getNearbyPeers(accountId);
     291             : }
     292             : 
     293             : void
     294           0 : updateProfile(const std::string& accountId,
     295             :               const std::string& displayName,
     296             :               const std::string& avatar,
     297             :               const std::string& fileType,
     298             :               int32_t flag)
     299             : {
     300           0 :     if (const auto acc = jami::Manager::instance().getAccount(accountId)) {
     301           0 :         acc->updateProfile(displayName, avatar, fileType, flag);
     302           0 :     }
     303           0 : }
     304             : 
     305             : int
     306           0 : getMessageStatus(uint64_t messageId)
     307             : {
     308           0 :     return jami::Manager::instance().getMessageStatus(messageId);
     309             : }
     310             : 
     311             : int
     312           0 : getMessageStatus(const std::string& accountId, uint64_t messageId)
     313             : {
     314           0 :     return jami::Manager::instance().getMessageStatus(accountId, messageId);
     315             : }
     316             : 
     317             : bool
     318           0 : cancelMessage(const std::string& accountId, uint64_t messageId)
     319             : {
     320           0 :     return {};
     321             : }
     322             : 
     323             : void
     324           5 : setIsComposing(const std::string& accountId, const std::string& conversationUri, bool isWriting)
     325             : {
     326           5 :     if (const auto acc = jami::Manager::instance().getAccount(accountId))
     327           5 :         acc->setIsComposing(conversationUri, isWriting);
     328           5 : }
     329             : 
     330             : bool
     331           2 : setMessageDisplayed(const std::string& accountId,
     332             :                     const std::string& conversationUri,
     333             :                     const std::string& messageId,
     334             :                     int status)
     335             : {
     336           2 :     if (const auto acc = jami::Manager::instance().getAccount(accountId))
     337           2 :         return acc->setMessageDisplayed(conversationUri, messageId, status);
     338           0 :     return false;
     339             : }
     340             : 
     341             : int32_t
     342           5 : addDevice(const std::string& accountId, const std::string& uri)
     343             : {
     344          20 :     JAMI_DEBUG("[LinkDevice {}] exportToPeer called.", accountId);
     345           5 :     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     346           5 :         return account->addDevice(uri);
     347           5 :     }
     348           0 :     return static_cast<int32_t>(jami::AccountManager::AddDeviceError::GENERIC);
     349             : }
     350             : 
     351             : bool
     352           4 : confirmAddDevice(const std::string& accountId, uint32_t op_id)
     353             : {
     354           4 :     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     355           4 :         return account->confirmAddDevice(op_id);
     356           4 :     }
     357           0 :     return false;
     358             : }
     359             : 
     360             : bool
     361           0 : cancelAddDevice(const std::string& accountId, uint32_t op_id)
     362             : {
     363           0 :     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     364           0 :         return account->cancelAddDevice(op_id);
     365           0 :     }
     366           0 :     return false;
     367             : }
     368             : 
     369             : bool
     370           7 : provideAccountAuthentication(const std::string& accountId,
     371             :                              const std::string& credentialsFromUser,
     372             :                              const std::string& scheme)
     373             : {
     374           7 :     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     375             :         // send the password to the channel for communicationg with the old device
     376           7 :         account->provideAccountAuthentication(credentialsFromUser, scheme);
     377           7 :         return true;
     378           7 :     }
     379           0 :     return false;
     380             : }
     381             : 
     382             : bool
     383           0 : exportToFile(const std::string& accountId,
     384             :              const std::string& destinationPath,
     385             :              const std::string& scheme,
     386             :              const std::string& password)
     387             : {
     388           0 :     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     389           0 :         return account->exportArchive(destinationPath, scheme, password);
     390           0 :     }
     391           0 :     return false;
     392             : }
     393             : 
     394             : bool
     395           0 : revokeDevice(const std::string& accountId,
     396             :              const std::string& deviceId,
     397             :              const std::string& scheme,
     398             :              const std::string& password)
     399             : {
     400           0 :     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
     401           0 :         return account->revokeDevice(deviceId, scheme, password);
     402           0 :     }
     403           0 :     return false;
     404             : }
     405             : 
     406             : std::map<std::string, std::string>
     407           0 : getKnownRingDevices(const std::string& accountId)
     408             : {
     409           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     410           0 :         return acc->getKnownDevices();
     411           0 :     return {};
     412             : }
     413             : 
     414             : bool
     415           4 : changeAccountPassword(const std::string& accountId, const std::string& password_old, const std::string& password_new)
     416             : {
     417           4 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     418           4 :         return acc->changeArchivePassword(password_old, password_new);
     419           0 :     return false;
     420             : }
     421             : 
     422             : /* contacts */
     423             : 
     424             : void
     425           0 : addContact(const std::string& accountId, const std::string& uri)
     426             : {
     427           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     428           0 :         return acc->addContact(uri);
     429             : }
     430             : 
     431             : void
     432           0 : removeContact(const std::string& accountId, const std::string& uri, bool ban)
     433             : {
     434           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     435           0 :         return acc->removeContact(uri, ban);
     436             : }
     437             : 
     438             : std::map<std::string, std::string>
     439           0 : getContactDetails(const std::string& accountId, const std::string& uri)
     440             : {
     441           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     442           0 :         return acc->getContactDetails(uri);
     443           0 :     return {};
     444             : }
     445             : 
     446             : std::vector<std::map<std::string, std::string>>
     447           1 : getContacts(const std::string& accountId)
     448             : {
     449           1 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     450           1 :         return acc->getContacts();
     451           0 :     return {};
     452             : }
     453             : 
     454             : /* contact requests */
     455             : std::vector<std::map<std::string, std::string>>
     456           6 : getTrustRequests(const std::string& accountId)
     457             : {
     458           6 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     459           6 :         return acc->getTrustRequests();
     460           0 :     return {};
     461             : }
     462             : 
     463             : bool
     464           0 : acceptTrustRequest(const std::string& accountId, const std::string& from)
     465             : {
     466           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     467           0 :         return acc->acceptTrustRequest(from);
     468           0 :     return false;
     469             : }
     470             : 
     471             : bool
     472           0 : discardTrustRequest(const std::string& accountId, const std::string& from)
     473             : {
     474           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     475           0 :         return acc->discardTrustRequest(from);
     476           0 :     return false;
     477             : }
     478             : 
     479             : void
     480           0 : sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload)
     481             : {
     482           0 :     if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
     483           0 :         acc->sendTrustRequest(to, payload);
     484           0 : }
     485             : 
     486             : /// This function is used as a base for new accounts for clients that support it
     487             : std::map<std::string, std::string>
     488         322 : getAccountTemplate(const std::string& accountType)
     489             : {
     490         322 :     if (accountType == Account::ProtocolNames::RING)
     491         598 :         return jami::JamiAccountConfig().toMap();
     492          23 :     else if (accountType == Account::ProtocolNames::SIP)
     493          46 :         return jami::SipAccountConfig().toMap();
     494           0 :     return {};
     495             : }
     496             : 
     497             : std::string
     498           0 : addAccount(const std::map<std::string, std::string>& details, const std::string& accountId)
     499             : {
     500           0 :     return jami::Manager::instance().addAccount(details, accountId);
     501             : }
     502             : 
     503             : void
     504           0 : monitor(bool continuous)
     505             : {
     506           0 :     return jami::Manager::instance().monitor(continuous);
     507             : }
     508             : 
     509             : std::vector<std::map<std::string, std::string>>
     510           0 : getConnectionList(const std::string& accountId, const std::string& conversationId)
     511             : {
     512           0 :     return jami::Manager::instance().getConnectionList(accountId, conversationId);
     513             : }
     514             : 
     515             : std::vector<std::map<std::string, std::string>>
     516           0 : getChannelList(const std::string& accountId, const std::string& connectionId)
     517             : {
     518           0 :     return jami::Manager::instance().getChannelList(accountId, connectionId);
     519             : }
     520             : 
     521             : void
     522           0 : removeAccount(const std::string& accountId)
     523             : {
     524           0 :     return jami::Manager::instance().removeAccount(accountId, true); // with 'flush' enabled
     525             : }
     526             : 
     527             : std::vector<std::string>
     528           0 : getAccountList()
     529             : {
     530           0 :     return jami::Manager::instance().getAccountList();
     531             : }
     532             : 
     533             : /**
     534             :  * Send the list of all codecs loaded to the client through DBus.
     535             :  * Can stay global, as only the active codecs will be set per accounts
     536             :  */
     537             : std::vector<unsigned>
     538           0 : getCodecList()
     539             : {
     540           0 :     std::vector<unsigned> list {jami::getSystemCodecContainer()->getSystemCodecInfoIdList(jami::MEDIA_ALL)};
     541           0 :     if (list.empty())
     542           0 :         jami::emitSignal<ConfigurationSignal::Error>(CODECS_NOT_LOADED);
     543           0 :     return list;
     544           0 : }
     545             : 
     546             : std::vector<std::string>
     547           0 : getSupportedTlsMethod()
     548             : {
     549           0 :     return SIPAccount::getSupportedTlsProtocols();
     550             : }
     551             : 
     552             : std::vector<std::string>
     553           0 : getSupportedCiphers(const std::string& accountId)
     554             : {
     555           0 :     if (auto sipaccount = jami::Manager::instance().getAccount<SIPAccount>(accountId))
     556           0 :         return SIPAccount::getSupportedTlsCiphers();
     557           0 :     JAMI_ERR("SIP account %s doesn't exist", accountId.c_str());
     558           0 :     return {};
     559             : }
     560             : 
     561             : bool
     562           0 : setCodecDetails(const std::string& accountId, const unsigned& codecId, const std::map<std::string, std::string>& details)
     563             : {
     564           0 :     auto acc = jami::Manager::instance().getAccount(accountId);
     565           0 :     if (!acc) {
     566           0 :         JAMI_ERR("Unable to find account %s. Unable to set codec details", accountId.c_str());
     567           0 :         return false;
     568             :     }
     569             : 
     570           0 :     auto codec = acc->searchCodecById(codecId, jami::MEDIA_ALL);
     571           0 :     if (!codec) {
     572           0 :         JAMI_ERR("Unable to find codec %d", codecId);
     573           0 :         return false;
     574             :     }
     575             :     try {
     576           0 :         if (codec->mediaType & jami::MEDIA_AUDIO) {
     577           0 :             if (auto foundCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec)) {
     578           0 :                 foundCodec->setCodecSpecifications(details);
     579           0 :                 jami::emitSignal<ConfigurationSignal::MediaParametersChanged>(accountId);
     580           0 :                 return true;
     581           0 :             }
     582             :         }
     583             : 
     584           0 :         if (codec->mediaType & jami::MEDIA_VIDEO) {
     585           0 :             if (auto foundCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec)) {
     586           0 :                 foundCodec->setCodecSpecifications(details);
     587           0 :                 JAMI_WARN("parameters for %s changed ", foundCodec->name.c_str());
     588           0 :                 if (auto call = jami::Manager::instance().getCurrentCall()) {
     589           0 :                     if (call->getVideoCodec() == foundCodec) {
     590           0 :                         JAMI_WARN("%s running. Need to restart encoding", foundCodec->name.c_str());
     591           0 :                         call->restartMediaSender();
     592             :                     }
     593           0 :                 }
     594           0 :                 jami::emitSignal<ConfigurationSignal::MediaParametersChanged>(accountId);
     595           0 :                 return true;
     596           0 :             }
     597             :         }
     598           0 :     } catch (const std::exception& e) {
     599           0 :         JAMI_ERR("Unable to set codec specifications: %s", e.what());
     600           0 :     }
     601             : 
     602           0 :     return false;
     603           0 : }
     604             : 
     605             : std::map<std::string, std::string>
     606           0 : getCodecDetails(const std::string& accountId, const unsigned& codecId)
     607             : {
     608           0 :     auto acc = jami::Manager::instance().getAccount(accountId);
     609           0 :     if (!acc) {
     610           0 :         JAMI_ERR("Unable to find account %s return default codec details", accountId.c_str());
     611           0 :         return jami::Account::getDefaultCodecDetails(codecId);
     612             :     }
     613             : 
     614           0 :     auto codec = acc->searchCodecById(codecId, jami::MEDIA_ALL);
     615           0 :     if (!codec) {
     616           0 :         jami::emitSignal<ConfigurationSignal::Error>(CODECS_NOT_LOADED);
     617           0 :         return {};
     618             :     }
     619             : 
     620           0 :     if (codec->mediaType & jami::MEDIA_AUDIO)
     621           0 :         if (auto foundCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec))
     622           0 :             return foundCodec->getCodecSpecifications();
     623             : 
     624           0 :     if (codec->mediaType & jami::MEDIA_VIDEO)
     625           0 :         if (auto foundCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec))
     626           0 :             return foundCodec->getCodecSpecifications();
     627             : 
     628           0 :     jami::emitSignal<ConfigurationSignal::Error>(CODECS_NOT_LOADED);
     629           0 :     return {};
     630           0 : }
     631             : 
     632             : std::vector<unsigned>
     633           0 : getActiveCodecList(const std::string& accountId)
     634             : {
     635           0 :     if (auto acc = jami::Manager::instance().getAccount(accountId))
     636           0 :         return acc->getActiveCodecs();
     637           0 :     JAMI_ERR("Unable to find account %s, returning default", accountId.c_str());
     638           0 :     return jami::Account::getDefaultCodecsId();
     639             : }
     640             : 
     641             : void
     642           0 : setActiveCodecList(const std::string& accountId, const std::vector<unsigned>& list)
     643             : {
     644           0 :     if (auto acc = jami::Manager::instance().getAccount(accountId)) {
     645           0 :         acc->setActiveCodecs(list);
     646           0 :         jami::Manager::instance().saveConfig(acc);
     647             :     } else {
     648           0 :         JAMI_ERR("Unable to find account %s", accountId.c_str());
     649           0 :     }
     650           0 : }
     651             : 
     652             : std::vector<std::string>
     653           0 : getAudioPluginList()
     654             : {
     655           0 :     return {PCM_DEFAULT, PCM_DMIX_DSNOOP};
     656             : }
     657             : 
     658             : void
     659           0 : setAudioPlugin(const std::string& audioPlugin)
     660             : {
     661           0 :     return jami::Manager::instance().setAudioPlugin(audioPlugin);
     662             : }
     663             : 
     664             : std::vector<std::string>
     665           0 : getAudioOutputDeviceList()
     666             : {
     667           0 :     return jami::Manager::instance().getAudioOutputDeviceList();
     668             : }
     669             : 
     670             : std::vector<std::string>
     671           0 : getAudioInputDeviceList()
     672             : {
     673           0 :     return jami::Manager::instance().getAudioInputDeviceList();
     674             : }
     675             : 
     676             : void
     677           0 : setAudioOutputDevice(int32_t index)
     678             : {
     679           0 :     return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::PLAYBACK);
     680             : }
     681             : 
     682             : void
     683           0 : setAudioInputDevice(int32_t index)
     684             : {
     685           0 :     return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::CAPTURE);
     686             : }
     687             : 
     688             : void
     689           0 : startAudio()
     690             : {
     691           0 :     jami::Manager::instance().startAudio();
     692           0 : }
     693             : 
     694             : void
     695           0 : setAudioRingtoneDevice(int32_t index)
     696             : {
     697           0 :     return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::RINGTONE);
     698             : }
     699             : 
     700             : std::vector<std::string>
     701           0 : getCurrentAudioDevicesIndex()
     702             : {
     703           0 :     return jami::Manager::instance().getCurrentAudioDevicesIndex();
     704             : }
     705             : 
     706             : int32_t
     707           0 : getAudioInputDeviceIndex(const std::string& name)
     708             : {
     709           0 :     return jami::Manager::instance().getAudioInputDeviceIndex(name);
     710             : }
     711             : 
     712             : int32_t
     713           0 : getAudioOutputDeviceIndex(const std::string& name)
     714             : {
     715           0 :     return jami::Manager::instance().getAudioOutputDeviceIndex(name);
     716             : }
     717             : 
     718             : std::string
     719           0 : getCurrentAudioOutputPlugin()
     720             : {
     721           0 :     auto plugin = jami::Manager::instance().getCurrentAudioOutputPlugin();
     722           0 :     JAMI_DBG("Get audio plugin %s", plugin.c_str());
     723           0 :     return plugin;
     724           0 : }
     725             : 
     726             : std::string
     727           0 : getNoiseSuppressState()
     728             : {
     729           0 :     return jami::Manager::instance().getNoiseSuppressState();
     730             : }
     731             : 
     732             : void
     733           0 : setNoiseSuppressState(const std::string& state)
     734             : {
     735           0 :     jami::Manager::instance().setNoiseSuppressState(state);
     736           0 : }
     737             : 
     738             : std::string
     739           0 : getEchoCancellationState()
     740             : {
     741           0 :     return jami::Manager::instance().getEchoCancellationState();
     742             : }
     743             : 
     744             : void
     745           0 : setEchoCancellationState(const std::string& state)
     746             : {
     747           0 :     jami::Manager::instance().setEchoCancellationState(state);
     748           0 : }
     749             : 
     750             : bool
     751           0 : getVoiceActivityDetectionState()
     752             : {
     753           0 :     return jami::Manager::instance().getVoiceActivityDetectionState();
     754             : }
     755             : 
     756             : void
     757           0 : setVoiceActivityDetectionState(bool state)
     758             : {
     759           0 :     jami::Manager::instance().setVoiceActivityDetectionState(state);
     760           0 : }
     761             : 
     762             : bool
     763           0 : isAgcEnabled()
     764             : {
     765           0 :     return jami::Manager::instance().isAGCEnabled();
     766             : }
     767             : 
     768             : void
     769           0 : setAgcState(bool enabled)
     770             : {
     771           0 :     jami::Manager::instance().setAGCState(enabled);
     772           0 : }
     773             : 
     774             : std::string
     775           0 : getRecordPath()
     776             : {
     777           0 :     return jami::Manager::instance().audioPreference.getRecordPath();
     778             : }
     779             : 
     780             : void
     781           0 : setRecordPath(const std::string& recPath)
     782             : {
     783           0 :     jami::Manager::instance().audioPreference.setRecordPath(recPath);
     784           0 : }
     785             : 
     786             : bool
     787           0 : getIsAlwaysRecording()
     788             : {
     789           0 :     return jami::Manager::instance().getIsAlwaysRecording();
     790             : }
     791             : 
     792             : void
     793           0 : setIsAlwaysRecording(bool rec)
     794             : {
     795           0 :     jami::Manager::instance().setIsAlwaysRecording(rec);
     796           0 : }
     797             : 
     798             : bool
     799           0 : getRecordPreview()
     800             : {
     801             : #ifdef ENABLE_VIDEO
     802           0 :     return jami::Manager::instance().videoPreferences.getRecordPreview();
     803             : #else
     804             :     return false;
     805             : #endif
     806             : }
     807             : 
     808             : void
     809           0 : setRecordPreview(bool rec)
     810             : {
     811             : #ifdef ENABLE_VIDEO
     812           0 :     jami::Manager::instance().videoPreferences.setRecordPreview(rec);
     813           0 :     jami::Manager::instance().saveConfig();
     814             : #endif
     815           0 : }
     816             : 
     817             : int32_t
     818           0 : getRecordQuality()
     819             : {
     820             : #ifdef ENABLE_VIDEO
     821           0 :     return jami::Manager::instance().videoPreferences.getRecordQuality();
     822             : #else
     823             :     return 0;
     824             : #endif
     825             : }
     826             : 
     827             : void
     828           0 : setRecordQuality(int32_t quality)
     829             : {
     830             : #ifdef ENABLE_VIDEO
     831           0 :     jami::Manager::instance().videoPreferences.setRecordQuality(quality);
     832           0 :     jami::Manager::instance().saveConfig();
     833             : #endif
     834           0 : }
     835             : 
     836             : int32_t
     837           0 : getHistoryLimit()
     838             : {
     839           0 :     return jami::Manager::instance().getHistoryLimit();
     840             : }
     841             : 
     842             : void
     843           0 : setHistoryLimit(int32_t days)
     844             : {
     845           0 :     jami::Manager::instance().setHistoryLimit(days);
     846           0 : }
     847             : 
     848             : int32_t
     849           0 : getRingingTimeout()
     850             : {
     851           0 :     return jami::Manager::instance().getRingingTimeout();
     852             : }
     853             : 
     854             : void
     855           0 : setRingingTimeout(int32_t timeout)
     856             : {
     857           0 :     jami::Manager::instance().setRingingTimeout(timeout);
     858           0 : }
     859             : 
     860             : std::vector<std::string>
     861           0 : getSupportedAudioManagers()
     862             : {
     863           0 :     return jami::AudioPreference::getSupportedAudioManagers();
     864             : }
     865             : 
     866             : bool
     867           0 : setAudioManager(const std::string& api)
     868             : {
     869           0 :     return jami::Manager::instance().setAudioManager(api);
     870             : }
     871             : 
     872             : std::string
     873           0 : getAudioManager()
     874             : {
     875           0 :     return jami::Manager::instance().getAudioManager();
     876             : }
     877             : 
     878             : void
     879           0 : setVolume(const std::string& device, double value)
     880             : {
     881           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver()) {
     882           0 :         JAMI_DBG("set volume for %s: %f", device.c_str(), value);
     883             : 
     884           0 :         if (device == "speaker")
     885           0 :             audiolayer->setPlaybackGain(value);
     886           0 :         else if (device == "mic")
     887           0 :             audiolayer->setCaptureGain(value);
     888             : 
     889           0 :         jami::emitSignal<ConfigurationSignal::VolumeChanged>(device, value);
     890             :     } else {
     891           0 :         JAMI_ERR("Audio layer not valid while updating volume");
     892           0 :     }
     893           0 : }
     894             : 
     895             : double
     896           0 : getVolume(const std::string& device)
     897             : {
     898           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver()) {
     899           0 :         if (device == "speaker")
     900           0 :             return audiolayer->getPlaybackGain();
     901           0 :         if (device == "mic")
     902           0 :             return audiolayer->getCaptureGain();
     903           0 :     }
     904             : 
     905           0 :     JAMI_ERR("Audio layer not valid while updating volume");
     906           0 :     return 0.0;
     907             : }
     908             : 
     909             : // FIXME: we should store "muteDtmf" instead of "playDtmf"
     910             : // in config and avoid negating like this
     911             : bool
     912           0 : isDtmfMuted()
     913             : {
     914           0 :     return not jami::Manager::instance().voipPreferences.getPlayDtmf();
     915             : }
     916             : 
     917             : void
     918           0 : muteDtmf(bool mute)
     919             : {
     920           0 :     jami::Manager::instance().voipPreferences.setPlayDtmf(not mute);
     921           0 : }
     922             : 
     923             : bool
     924           0 : isCaptureMuted()
     925             : {
     926           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver())
     927           0 :         return audiolayer->isCaptureMuted();
     928             : 
     929           0 :     JAMI_ERR("Audio layer not valid");
     930           0 :     return false;
     931             : }
     932             : 
     933             : void
     934           0 : muteCapture(bool mute)
     935             : {
     936           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver())
     937           0 :         return audiolayer->muteCapture(mute);
     938             : 
     939           0 :     JAMI_ERR("Audio layer not valid");
     940           0 :     return;
     941             : }
     942             : 
     943             : bool
     944           0 : isPlaybackMuted()
     945             : {
     946           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver())
     947           0 :         return audiolayer->isPlaybackMuted();
     948             : 
     949           0 :     JAMI_ERR("Audio layer not valid");
     950           0 :     return false;
     951             : }
     952             : 
     953             : void
     954           0 : mutePlayback(bool mute)
     955             : {
     956           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver())
     957           0 :         return audiolayer->mutePlayback(mute);
     958             : 
     959           0 :     JAMI_ERR("Audio layer not valid");
     960           0 :     return;
     961             : }
     962             : 
     963             : bool
     964           0 : isRingtoneMuted()
     965             : {
     966           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver())
     967           0 :         return audiolayer->isRingtoneMuted();
     968             : 
     969           0 :     JAMI_ERR("Audio layer not valid");
     970           0 :     return false;
     971             : }
     972             : 
     973             : void
     974           0 : muteRingtone(bool mute)
     975             : {
     976           0 :     if (auto audiolayer = jami::Manager::instance().getAudioDriver())
     977           0 :         return audiolayer->muteRingtone(mute);
     978             : 
     979           0 :     JAMI_ERR("Audio layer not valid");
     980           0 :     return;
     981             : }
     982             : 
     983             : void
     984           0 : setAccountsOrder(const std::string& order)
     985             : {
     986           0 :     jami::Manager::instance().setAccountsOrder(order);
     987           0 : }
     988             : 
     989             : std::string
     990           0 : getAddrFromInterfaceName(const std::string& interface)
     991             : {
     992           0 :     return dhtnet::ip_utils::getInterfaceAddr(interface, AF_INET);
     993             : }
     994             : 
     995             : std::vector<std::string>
     996           0 : getAllIpInterface()
     997             : {
     998           0 :     return dhtnet::ip_utils::getAllIpInterface();
     999             : }
    1000             : 
    1001             : std::vector<std::string>
    1002           0 : getAllIpInterfaceByName()
    1003             : {
    1004           0 :     return dhtnet::ip_utils::getAllIpInterfaceByName();
    1005             : }
    1006             : 
    1007             : std::vector<std::map<std::string, std::string>>
    1008           0 : getCredentials(const std::string& accountId)
    1009             : {
    1010           0 :     if (auto sipaccount = jami::Manager::instance().getAccount<SIPAccount>(accountId))
    1011           0 :         return sipaccount->getCredentials();
    1012           0 :     return {};
    1013             : }
    1014             : 
    1015             : void
    1016           0 : setCredentials(const std::string& accountId, const std::vector<std::map<std::string, std::string>>& details)
    1017             : {
    1018           0 :     if (auto sipaccount = jami::Manager::instance().getAccount<SIPAccount>(accountId)) {
    1019           0 :         sipaccount->doUnregister();
    1020           0 :         sipaccount->editConfig([&](jami::SipAccountConfig& config) { config.setCredentials(details); });
    1021           0 :         sipaccount->loadConfig();
    1022           0 :         if (sipaccount->isEnabled())
    1023           0 :             sipaccount->doRegister();
    1024           0 :         jami::Manager::instance().saveConfig(sipaccount);
    1025           0 :     }
    1026           0 : }
    1027             : 
    1028             : void
    1029           0 : connectivityChanged()
    1030             : {
    1031           0 :     JAMI_WARN("received connectivity changed - attempting to re-connect enabled accounts");
    1032             : 
    1033             :     // reset the UPnP context
    1034             : #if !(defined(TARGET_OS_IOS) && TARGET_OS_IOS)
    1035             :     try {
    1036           0 :         jami::Manager::instance().upnpContext()->connectivityChanged();
    1037           0 :     } catch (std::runtime_error& e) {
    1038           0 :         JAMI_ERR("UPnP context error: %s", e.what());
    1039           0 :     }
    1040             : #endif
    1041             : 
    1042           0 :     for (const auto& account : jami::Manager::instance().getAllAccounts()) {
    1043           0 :         account->connectivityChanged();
    1044           0 :     }
    1045           0 : }
    1046             : 
    1047             : bool
    1048           3 : lookupName(const std::string& account, const std::string& nameserver, const std::string& name)
    1049             : {
    1050           3 :     if (account.empty()) {
    1051             :         auto cb =
    1052           0 :             [name](const std::string& regName, const std::string& address, jami::NameDirectory::Response response) {
    1053           0 :                 jami::emitSignal<libjami::ConfigurationSignal::RegisteredNameFound>("",
    1054           0 :                                                                                     name,
    1055             :                                                                                     (int) response,
    1056             :                                                                                     address,
    1057             :                                                                                     regName);
    1058           0 :             };
    1059           0 :         if (nameserver.empty())
    1060           0 :             jami::NameDirectory::lookupUri(name, "", cb);
    1061             :         else
    1062           0 :             jami::NameDirectory::instance(nameserver).lookupName(name, cb);
    1063           0 :         return true;
    1064           3 :     } else if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
    1065           3 :         acc->lookupName(name);
    1066           3 :         return true;
    1067           3 :     }
    1068           0 :     JAMI_ERROR("lookupName: Unknown account: {}", account);
    1069           0 :     return false;
    1070             : }
    1071             : 
    1072             : bool
    1073           3 : lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address)
    1074             : {
    1075           3 :     if (account.empty()) {
    1076           0 :         jami::NameDirectory::instance(nameserver)
    1077           0 :             .lookupAddress(address,
    1078           0 :                            [address](const std::string& regName,
    1079             :                                      const std::string& addr,
    1080             :                                      jami::NameDirectory::Response response) {
    1081           0 :                                jami::emitSignal<libjami::ConfigurationSignal::RegisteredNameFound>("",
    1082           0 :                                                                                                    address,
    1083             :                                                                                                    (int) response,
    1084             :                                                                                                    addr,
    1085             :                                                                                                    regName);
    1086           0 :                            });
    1087           0 :         return true;
    1088           3 :     } else if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
    1089           3 :         acc->lookupAddress(address);
    1090           3 :         return true;
    1091           3 :     }
    1092           0 :     JAMI_ERROR("lookupAddress: Unknown account: {}", account);
    1093           0 :     return false;
    1094             : }
    1095             : 
    1096             : bool
    1097           0 : searchUser(const std::string& account, const std::string& query)
    1098             : {
    1099           0 :     if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
    1100           0 :         return acc->searchUser(query);
    1101           0 :     }
    1102           0 :     return false;
    1103             : }
    1104             : 
    1105             : bool
    1106           1 : registerName(const std::string& account, const std::string& name, const std::string& scheme, const std::string& password)
    1107             : {
    1108           1 :     if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
    1109           1 :         acc->registerName(name, scheme, password);
    1110           1 :         return true;
    1111           1 :     }
    1112           0 :     JAMI_ERROR("registerName: Unknown account: {}", account);
    1113           0 :     return false;
    1114             : }
    1115             : 
    1116             : void
    1117           0 : setPushNotificationToken(const std::string& token)
    1118             : {
    1119           0 :     for (const auto& account : jami::Manager::instance().getAllAccounts()) {
    1120           0 :         account->setPushNotificationToken(token);
    1121           0 :     }
    1122           0 : }
    1123             : 
    1124             : void
    1125           0 : setPushNotificationTopic(const std::string& topic)
    1126             : {
    1127           0 :     for (const auto& account : jami::Manager::instance().getAllAccounts()) {
    1128           0 :         account->setPushNotificationTopic(topic);
    1129           0 :     }
    1130           0 : }
    1131             : 
    1132             : void
    1133           0 : setPushNotificationConfig(const std::map<std::string, std::string>& data)
    1134             : {
    1135           0 :     for (const auto& account : jami::Manager::instance().getAllAccounts()) {
    1136           0 :         account->setPushNotificationConfig(data);
    1137           0 :     }
    1138           0 : }
    1139             : 
    1140             : void
    1141           0 : pushNotificationReceived(const std::string& from, const std::map<std::string, std::string>& data)
    1142             : {
    1143             :     try {
    1144           0 :         auto it = data.find("to");
    1145           0 :         if (it != data.end()) {
    1146           0 :             if (auto account = jami::Manager::instance().getAccount<JamiAccount>(it->second))
    1147           0 :                 account->pushNotificationReceived(from, data);
    1148             :         }
    1149             : #if defined(__ANDROID__) || defined(ANDROID) || defined(__Apple__)
    1150             :         else {
    1151             :             for (const auto& sipAccount : jami::Manager::instance().getAllAccounts<SIPAccount>()) {
    1152             :                 sipAccount->pushNotificationReceived(from, data);
    1153             :             }
    1154             :         }
    1155             : #endif
    1156           0 :     } catch (const std::exception& e) {
    1157           0 :         JAMI_ERR("Error processing push notification: %s", e.what());
    1158           0 :     }
    1159           0 : }
    1160             : 
    1161             : bool
    1162           0 : isAudioMeterActive(const std::string& id)
    1163             : {
    1164           0 :     return jami::Manager::instance().getRingBufferPool().isAudioMeterActive(id);
    1165             : }
    1166             : 
    1167             : void
    1168           0 : setAudioMeterState(const std::string& id, bool state)
    1169             : {
    1170           0 :     jami::Manager::instance().getRingBufferPool().setAudioMeterState(id, state);
    1171           0 : }
    1172             : 
    1173             : void
    1174           0 : setDefaultModerator(const std::string& accountId, const std::string& peerURI, bool state)
    1175             : {
    1176           0 :     jami::Manager::instance().setDefaultModerator(accountId, peerURI, state);
    1177           0 : }
    1178             : 
    1179             : std::vector<std::string>
    1180           0 : getDefaultModerators(const std::string& accountId)
    1181             : {
    1182           0 :     return jami::Manager::instance().getDefaultModerators(accountId);
    1183             : }
    1184             : 
    1185             : void
    1186           0 : enableLocalModerators(const std::string& accountId, bool isModEnabled)
    1187             : {
    1188           0 :     jami::Manager::instance().enableLocalModerators(accountId, isModEnabled);
    1189           0 : }
    1190             : 
    1191             : bool
    1192           0 : isLocalModeratorsEnabled(const std::string& accountId)
    1193             : {
    1194           0 :     return jami::Manager::instance().isLocalModeratorsEnabled(accountId);
    1195             : }
    1196             : 
    1197             : void
    1198           0 : setAllModerators(const std::string& accountId, bool allModerators)
    1199             : {
    1200           0 :     jami::Manager::instance().setAllModerators(accountId, allModerators);
    1201           0 : }
    1202             : 
    1203             : bool
    1204           0 : isAllModerators(const std::string& accountId)
    1205             : {
    1206           0 :     return jami::Manager::instance().isAllModerators(accountId);
    1207             : }
    1208             : 
    1209             : void
    1210           0 : setResourceDirPath(const std::string& resourceDir)
    1211             : {
    1212           0 :     jami::fileutils::set_resource_dir_path(resourceDir);
    1213           0 : }
    1214             : 
    1215             : } // namespace libjami

Generated by: LCOV version 1.14