LCOV - code coverage report
Current view: top level - src - account.cpp (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 138 236 58.5 %
Date: 2024-12-21 08:56:24 Functions: 26 40 65.0 %

          Line data    Source code
       1             : /*
       2             :  *  Copyright (C) 2004-2024 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             : #include "media/media_codec.h"
      19             : #ifdef HAVE_CONFIG_H
      20             : #include "config.h"
      21             : #endif
      22             : #include "account.h"
      23             : 
      24             : #include <algorithm>
      25             : #include <iterator>
      26             : #include <mutex>
      27             : 
      28             : #ifdef ENABLE_VIDEO
      29             : #include "libav_utils.h"
      30             : #endif
      31             : 
      32             : #include "logger.h"
      33             : #include "manager.h"
      34             : 
      35             : #include <opendht/rng.h>
      36             : 
      37             : #include "client/ring_signal.h"
      38             : #include "account_schema.h"
      39             : #include "jami/account_const.h"
      40             : #include "string_utils.h"
      41             : #include "fileutils.h"
      42             : #include "config/yamlparser.h"
      43             : #include "system_codec_container.h"
      44             : #include "vcard.h"
      45             : 
      46             : #pragma GCC diagnostic push
      47             : #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
      48             : #include <yaml-cpp/yaml.h>
      49             : #pragma GCC diagnostic pop
      50             : 
      51             : #include "compiler_intrinsics.h"
      52             : #include "jami/account_const.h"
      53             : 
      54             : #include <dhtnet/upnp/upnp_control.h>
      55             : #include <dhtnet/ip_utils.h>
      56             : 
      57             : #include <fmt/ranges.h>
      58             : 
      59             : using namespace std::literals;
      60             : 
      61             : namespace jami {
      62             : 
      63             : // For portability, do not specify the absolute filename of the ringtone.
      64             : // Instead, specify its base name to be looked in
      65             : // JAMI_DATADIR/ringtones/, where JAMI_DATADIR is a preprocessor macro denoting
      66             : // the data directory prefix that must be set at build time.
      67             : const std::string Account::DEFAULT_USER_AGENT = Account::getDefaultUserAgent();
      68             : 
      69         808 : Account::Account(const std::string& accountId)
      70         808 :     : rand(Manager::instance().getSeededRandomEngine())
      71         808 :     , accountID_(accountId)
      72         808 :     , systemCodecContainer_(getSystemCodecContainer())
      73        2424 :     , idPath_(fileutils::get_data_dir() / accountId)
      74             : {
      75             :     // Initialize the codec order, used when creating a new account
      76         808 :     loadDefaultCodecs();
      77         808 : }
      78             : 
      79         808 : Account::~Account() {}
      80             : 
      81             : void
      82         779 : Account::hangupCalls()
      83             : {
      84         803 :     for (const auto& callId : callSet_.getCallIds())
      85         803 :         Manager::instance().hangupCall(getAccountID(), callId);
      86         779 : }
      87             : 
      88             : void
      89        1033 : Account::updateUpnpController()
      90             : {
      91        1033 :     std::lock_guard lk {upnp_mtx};
      92             : 
      93        1033 :     if (not config().upnpEnabled or not isUsable()) {
      94         238 :         upnpCtrl_.reset();
      95         238 :         return;
      96             :     }
      97             : 
      98             :     // UPNP enabled. Create new controller if needed.
      99         795 :     if (not upnpCtrl_) {
     100         778 :         upnpCtrl_ = std::make_shared<dhtnet::upnp::Controller>(Manager::instance().upnpContext());
     101         778 :         if (not upnpCtrl_) {
     102           0 :             throw std::runtime_error("Failed to create a UPNP Controller instance!");
     103             :         }
     104             :     }
     105        1033 : }
     106             : 
     107             : void
     108        5154 : Account::setRegistrationState(RegistrationState state,
     109             :                               int detail_code,
     110             :                               const std::string& detail_str)
     111             : {
     112        5154 :     if (state != registrationState_) {
     113        3709 :         registrationState_ = state;
     114             :         // Notify the client
     115        7418 :         runOnMainThread([accountId = accountID_,
     116             :                          state = mapStateNumberToString(registrationState_),
     117             :                          detail_code,
     118             :                          detail_str,
     119        3709 :                          details = getVolatileAccountDetails()] {
     120        3709 :             emitSignal<libjami::ConfigurationSignal::RegistrationStateChanged>(accountId,
     121        3709 :                                                                              state,
     122             :                                                                              detail_code,
     123        3709 :                                                                              detail_str);
     124             : 
     125        3709 :             emitSignal<libjami::ConfigurationSignal::VolatileDetailsChanged>(accountId, details);
     126        3709 :         });
     127             :     }
     128        5154 : }
     129             : 
     130             : void
     131         808 : Account::loadDefaultCodecs()
     132             : {
     133             :     // default codec are system codecs
     134         808 :     const auto& systemCodecList = systemCodecContainer_->getSystemCodecInfoList();
     135         808 :     accountCodecInfoList_.clear();
     136         808 :     accountCodecInfoList_.reserve(systemCodecList.size());
     137       10504 :     for (const auto& systemCodec : systemCodecList) {
     138             :         // As defined in SDP RFC, only select a codec if it can encode and decode
     139        9696 :         if ((systemCodec->codecType & CODEC_ENCODER_DECODER) != CODEC_ENCODER_DECODER)
     140           0 :             continue;
     141             : 
     142        9696 :         if (systemCodec->mediaType & MEDIA_AUDIO) {
     143        6464 :             accountCodecInfoList_.emplace_back(std::make_shared<SystemAudioCodecInfo>(
     144       12928 :                 *std::static_pointer_cast<SystemAudioCodecInfo>(systemCodec)));
     145             :         }
     146             : 
     147        9696 :         if (systemCodec->mediaType & MEDIA_VIDEO) {
     148        3232 :             accountCodecInfoList_.emplace_back(std::make_shared<SystemVideoCodecInfo>(
     149        6464 :                 *std::static_pointer_cast<SystemVideoCodecInfo>(systemCodec)));
     150             :         }
     151             :     }
     152         808 : }
     153             : 
     154             : void
     155         823 : Account::loadConfig() {
     156         823 :     setActiveCodecs(config_->activeCodecs);
     157             : 
     158             :     // Try to get the client-defined resource base directory, if any. If not set, use the default
     159             :     // JAMI_DATADIR that was set at build time.
     160         823 :     auto ringtoneDir = fileutils::get_resource_dir_path() / RINGDIR;
     161         823 :     ringtonePath_ = fileutils::getFullPath(ringtoneDir, config_->ringtonePath);
     162             :     // If the user defined a custom ringtone, the file may not exists
     163             :     // In this case, fallback on the default ringtone path
     164         823 :     if (not std::filesystem::is_regular_file(ringtonePath_)) {
     165        2469 :         JAMI_WARNING("Ringtone {} is not a valid file", ringtonePath_);
     166         823 :         config_->ringtonePath = DEFAULT_RINGTONE_PATH;
     167         823 :         ringtonePath_ = fileutils::getFullPath(ringtoneDir, config_->ringtonePath);
     168             :     }
     169         823 :     updateUpnpController();
     170         823 : }
     171             : 
     172             : void
     173          52 : Account::saveConfig() const
     174             : {
     175          52 :     Manager::instance().saveConfig();
     176          52 : }
     177             : 
     178             : std::map<std::string, std::string>
     179        4659 : Account::getVolatileAccountDetails() const
     180             : {
     181        9318 :     return {{Conf::CONFIG_ACCOUNT_REGISTRATION_STATUS, mapStateNumberToString(registrationState_)},
     182       18636 :             {libjami::Account::VolatileProperties::ACTIVE, active_ ? TRUE_STR : FALSE_STR}};
     183             : }
     184             : 
     185             : std::map<std::string, std::string>
     186           0 : Account::getProfileVcard() const
     187             : {
     188             :     try {
     189           0 :         auto path = idPath_ / "profile.vcf";
     190           0 :         if (!std::filesystem::exists(path))
     191           0 :             return {};
     192           0 :         return vCard::utils::toMap(fileutils::loadTextFile(path));
     193           0 :     } catch (const std::exception& e) {
     194           0 :         JAMI_ERROR("Error reading profile: {}", e.what());
     195           0 :         return {};
     196           0 :     }
     197             : }
     198             : 
     199             : bool
     200        1753 : Account::hasActiveCodec(MediaType mediaType) const
     201             : {
     202       21881 :     for (auto& codecIt : accountCodecInfoList_)
     203       20275 :         if ((codecIt->mediaType & mediaType) && codecIt->isActive)
     204         147 :             return true;
     205        1606 :     return false;
     206             : }
     207             : 
     208             : void
     209         823 : Account::setActiveCodecs(const std::vector<unsigned>& list)
     210             : {
     211             :     // first clear the previously stored codecs
     212             :     // TODO: mutex to protect isActive
     213         823 :     setAllCodecsActive(MEDIA_ALL, false);
     214             : 
     215             :     // list contains the ordered payload of active codecs picked by the user for this account
     216             :     // we used the codec vector to save the order.
     217         823 :     uint16_t order = 1;
     218         883 :     for (const auto& item : list) {
     219          60 :         if (auto accCodec = searchCodecById(item, MEDIA_ALL)) {
     220          60 :             accCodec->isActive = true;
     221          60 :             accCodec->order = order;
     222          60 :             ++order;
     223          60 :         }
     224             :     }
     225         823 :     sortCodec();
     226         823 : }
     227             : 
     228             : void
     229         823 : Account::sortCodec()
     230             : {
     231         823 :     std::sort(std::begin(accountCodecInfoList_),
     232         823 :               std::end(accountCodecInfoList_),
     233       18524 :               [](const std::shared_ptr<SystemCodecInfo>& a,
     234       18524 :                  const std::shared_ptr<SystemCodecInfo>& b) { return a->order < b->order; });
     235         823 : }
     236             : 
     237             : std::string
     238        8368 : Account::mapStateNumberToString(RegistrationState state)
     239             : {
     240             : #define CASE_STATE(X) \
     241             :     case RegistrationState::X: \
     242             :         return #X
     243             : 
     244        8368 :     switch (state) {
     245           0 :         CASE_STATE(UNLOADED);
     246        3060 :         CASE_STATE(UNREGISTERED);
     247        1480 :         CASE_STATE(TRYING);
     248        2260 :         CASE_STATE(REGISTERED);
     249           0 :         CASE_STATE(ERROR_GENERIC);
     250           0 :         CASE_STATE(ERROR_AUTH);
     251           0 :         CASE_STATE(ERROR_NETWORK);
     252           0 :         CASE_STATE(ERROR_HOST);
     253           0 :         CASE_STATE(ERROR_SERVICE_UNAVAILABLE);
     254           0 :         CASE_STATE(ERROR_NEED_MIGRATION);
     255        1568 :         CASE_STATE(INITIALIZING);
     256           0 :     default:
     257           0 :         return libjami::Account::States::ERROR_GENERIC;
     258             :     }
     259             : 
     260             : #undef CASE_STATE
     261             : }
     262             : 
     263             : std::vector<unsigned>
     264           0 : Account::getDefaultCodecsId()
     265             : {
     266           0 :     return getSystemCodecContainer()->getSystemCodecInfoIdList(MEDIA_ALL);
     267             : }
     268             : 
     269             : std::map<std::string, std::string>
     270           0 : Account::getDefaultCodecDetails(const unsigned& codecId)
     271             : {
     272           0 :     auto codec = jami::getSystemCodecContainer()->searchCodecById(codecId, jami::MEDIA_ALL);
     273           0 :     if (codec) {
     274           0 :         if (codec->mediaType & jami::MEDIA_AUDIO) {
     275           0 :             auto audioCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec);
     276           0 :             return audioCodec->getCodecSpecifications();
     277           0 :         }
     278           0 :         if (codec->mediaType & jami::MEDIA_VIDEO) {
     279           0 :             auto videoCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec);
     280           0 :             return videoCodec->getCodecSpecifications();
     281           0 :         }
     282             :     }
     283           0 :     return {};
     284           0 : }
     285             : 
     286             : /**
     287             :  * Get the UPnP IP (external router) address.
     288             :  * If use UPnP is set to false, the address will be empty.
     289             :  */
     290             : dhtnet::IpAddr
     291           0 : Account::getUPnPIpAddress() const
     292             : {
     293           0 :     std::lock_guard lk(upnp_mtx);
     294           0 :     if (upnpCtrl_)
     295           0 :         return upnpCtrl_->getExternalIP();
     296           0 :     return {};
     297           0 : }
     298             : 
     299             : /**
     300             :  * returns whether or not UPnP is enabled and active_
     301             :  * ie: if it is able to make port mappings
     302             :  */
     303             : bool
     304         561 : Account::getUPnPActive() const
     305             : {
     306         561 :     std::lock_guard lk(upnp_mtx);
     307         561 :     if (upnpCtrl_)
     308         423 :         return upnpCtrl_->isReady();
     309         138 :     return false;
     310         561 : }
     311             : 
     312             : /*
     313             :  * private account codec searching functions
     314             :  *
     315             :  * */
     316             : std::shared_ptr<SystemCodecInfo>
     317          60 : Account::searchCodecById(unsigned codecId, MediaType mediaType)
     318             : {
     319          60 :     if (mediaType != MEDIA_NONE) {
     320         185 :         for (auto& codecIt : accountCodecInfoList_) {
     321         185 :             if ((codecIt->id == codecId)
     322         185 :                 && (codecIt->mediaType & mediaType))
     323          60 :                 return codecIt;
     324             :         }
     325             :     }
     326           0 :     return {};
     327             : }
     328             : 
     329             : std::shared_ptr<SystemCodecInfo>
     330           0 : Account::searchCodecByName(const std::string& name, MediaType mediaType)
     331             : {
     332           0 :     if (mediaType != MEDIA_NONE) {
     333           0 :         for (auto& codecIt : accountCodecInfoList_) {
     334           0 :             if (codecIt->name == name
     335           0 :                 && (codecIt->mediaType & mediaType))
     336           0 :                 return codecIt;
     337             :         }
     338             :     }
     339           0 :     return {};
     340             : }
     341             : 
     342             : std::shared_ptr<SystemCodecInfo>
     343           0 : Account::searchCodecByPayload(unsigned payload, MediaType mediaType)
     344             : {
     345           0 :     if (mediaType != MEDIA_NONE) {
     346           0 :         for (auto& codecIt : accountCodecInfoList_) {
     347           0 :             if ((codecIt->payloadType == payload)
     348           0 :                 && (codecIt->mediaType & mediaType))
     349           0 :                 return codecIt;
     350             :         }
     351             :     }
     352           0 :     return {};
     353             : }
     354             : 
     355             : std::vector<unsigned>
     356         823 : Account::getActiveCodecs(MediaType mediaType) const
     357             : {
     358         823 :     if (mediaType == MEDIA_NONE)
     359           0 :         return {};
     360             : 
     361         823 :     std::vector<unsigned> idList;
     362       10699 :     for (auto& codecIt : accountCodecInfoList_) {
     363        9876 :         if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
     364        2685 :             idList.push_back(codecIt->id);
     365             :     }
     366         823 :     return idList;
     367         823 : }
     368             : 
     369             : std::vector<unsigned>
     370           0 : Account::getAccountCodecInfoIdList(MediaType mediaType) const
     371             : {
     372           0 :     if (mediaType == MEDIA_NONE)
     373           0 :         return {};
     374             : 
     375           0 :     std::vector<unsigned> idList;
     376           0 :     for (auto& codecIt : accountCodecInfoList_) {
     377           0 :         if (codecIt->mediaType & mediaType)
     378           0 :             idList.push_back(codecIt->id);
     379             :     }
     380             : 
     381           0 :     return idList;
     382           0 : }
     383             : 
     384             : void
     385         871 : Account::setAllCodecsActive(MediaType mediaType, bool active)
     386             : {
     387         871 :     if (mediaType == MEDIA_NONE)
     388           0 :         return;
     389       11323 :     for (auto& codecIt : accountCodecInfoList_) {
     390       10452 :         if (codecIt->mediaType & mediaType)
     391       10164 :             codecIt->isActive = active;
     392             :     }
     393             : }
     394             : 
     395             : void
     396        3116 : Account::setCodecActive(unsigned codecId)
     397             : {
     398       40508 :     for (auto& codecIt : accountCodecInfoList_) {
     399       37392 :         if (codecIt->avcodecId == codecId)
     400        2337 :             codecIt->isActive = true;
     401             :     }
     402        3116 : }
     403             : 
     404             : void
     405           0 : Account::setCodecInactive(unsigned codecId)
     406             : {
     407           0 :     for (auto& codecIt : accountCodecInfoList_) {
     408           0 :         if (codecIt->avcodecId == codecId)
     409           0 :             codecIt->isActive = false;
     410             :     }
     411           0 : }
     412             : 
     413             : std::vector<std::shared_ptr<SystemCodecInfo>>
     414         790 : Account::getActiveAccountCodecInfoList(MediaType mediaType) const
     415             : {
     416         790 :     if (mediaType == MEDIA_NONE)
     417           0 :         return {};
     418             : 
     419         790 :     std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecList;
     420       10270 :     for (auto& codecIt : accountCodecInfoList_) {
     421        9480 :         if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
     422        1365 :             accountCodecList.push_back(codecIt);
     423             :     }
     424             : 
     425         790 :     return accountCodecList;
     426         790 : }
     427             : 
     428             : const std::string&
     429         775 : Account::getUserAgentName()
     430             : {
     431         775 :     return config_->customUserAgent.empty() ? DEFAULT_USER_AGENT : config_->customUserAgent;
     432             : }
     433             : 
     434             : std::string
     435          44 : Account::getDefaultUserAgent()
     436             : {
     437          88 :     return fmt::format("{:s} {:s} ({:s})", PACKAGE_NAME, libjami::version(), jami::platform());
     438             : }
     439             : 
     440             : void
     441           0 : Account::addDefaultModerator(const std::string& uri)
     442             : {
     443           0 :     config_->defaultModerators.insert(uri);
     444           0 : }
     445             : 
     446             : void
     447           0 : Account::removeDefaultModerator(const std::string& uri)
     448             : {
     449           0 :     config_->defaultModerators.erase(uri);
     450           0 : }
     451             : 
     452             : bool
     453         859 : Account::meetMinimumRequiredVersion(const std::vector<unsigned>& version,
     454             :                                     const std::vector<unsigned>& minRequiredVersion)
     455             : {
     456         876 :     for (size_t i = 0; i < minRequiredVersion.size(); i++) {
     457         872 :         if (i == version.size() or version[i] < minRequiredVersion[i])
     458           5 :             return false;
     459         867 :         if (version[i] > minRequiredVersion[i])
     460         850 :             return true;
     461             :     }
     462           4 :     return true;
     463             : }
     464             : 
     465             : bool
     466           0 : Account::setPushNotificationConfig(const std::map<std::string, std::string>& data)
     467             : {
     468           0 :     std::lock_guard lock(configurationMutex_);
     469           0 :     auto platform = data.find("platform");
     470           0 :     auto topic = data.find("topic");
     471           0 :     auto token = data.find("token");
     472           0 :     bool changed = false;
     473           0 :     if (platform != data.end() && config_->platform != platform->second) {
     474           0 :         config_->platform = platform->second;
     475           0 :         changed = true;
     476             :     }
     477           0 :     if (topic != data.end() && config_->notificationTopic != topic->second) {
     478           0 :         config_->notificationTopic = topic->second;
     479           0 :         changed = true;
     480             :     }
     481           0 :     if (token != data.end() && config_->deviceKey != token->second) {
     482           0 :         config_->deviceKey = token->second;
     483           0 :         changed = true;
     484             :     }
     485           0 :     if (changed)
     486           0 :         saveConfig();
     487           0 :     return changed;
     488           0 : }
     489             : 
     490             : } // namespace jami

Generated by: LCOV version 1.14