LCOV - code coverage report
Current view: top level - foo/src - account.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 73 112 65.2 %
Date: 2025-08-24 09:11:10 Functions: 42 57 73.7 %

          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             : #pragma once
      18             : 
      19             : #ifdef HAVE_CONFIG_H
      20             : #include "config.h"
      21             : #endif
      22             : 
      23             : #include "client/ring_signal.h"
      24             : #include "configurationmanager_interface.h"
      25             : #include "noncopyable.h"
      26             : #include "config/serializable.h"
      27             : #include "registration_states.h"
      28             : #include "im/message_engine.h"
      29             : #include "media/media_codec.h"
      30             : #include "media/media_attribute.h"
      31             : #include "logger.h"
      32             : #include "compiler_intrinsics.h" // include the "UNUSED" macro
      33             : #include "call_set.h"
      34             : #include "account_config.h"
      35             : 
      36             : #include <dhtnet/ip_utils.h>
      37             : #include <dhtnet/upnp/upnp_control.h>
      38             : 
      39             : #include <functional>
      40             : #include <string>
      41             : #include <vector>
      42             : #include <memory>
      43             : #include <map>
      44             : #include <set>
      45             : #include <random>
      46             : #include <stdexcept>
      47             : #include <atomic>
      48             : #include <mutex>
      49             : #include <chrono>
      50             : 
      51             : namespace Json {
      52             : class Value;
      53             : }
      54             : 
      55             : namespace dht {
      56             : namespace crypto {
      57             : struct Certificate;
      58             : }
      59             : }
      60             : 
      61             : namespace jami {
      62             : static constexpr uint64_t JAMI_ID_MAX_VAL = 9007199254740992;
      63             : constexpr static const char RINGDIR[] = "ringtones";
      64             : 
      65             : class Call;
      66             : class SystemCodecContainer;
      67             : 
      68             : class VoipLinkException : public std::runtime_error
      69             : {
      70             : public:
      71           1 :     VoipLinkException(const std::string& str = "")
      72           1 :         : std::runtime_error("VoipLinkException occurred: " + str)
      73           1 :     {}
      74             : };
      75             : 
      76             : /**
      77             :  * @file account.h
      78             :  * @brief Interface to protocol account (ex: SIPAccount)
      79             :  * It can be enable on loading or activate after.
      80             :  * It contains account, configuration, VoIP Link and Calls (inside the VoIPLink)
      81             :  */
      82             : 
      83             : class Account : public std::enable_shared_from_this<Account>
      84             : {
      85             : public:
      86             :     Account(const std::string& accountID);
      87             : 
      88             :     /**
      89             :      * Virtual destructor
      90             :      */
      91             :     virtual ~Account();
      92             : 
      93             :     /**
      94             :      * Free all ressources related to this account.
      95             :      *   ***Current calls using this account are HANG-UP***
      96             :      */
      97             :     void hangupCalls();
      98             : 
      99             :     virtual std::unique_ptr<AccountConfig> buildConfig() const = 0;
     100             : 
     101           0 :     void setConfig(std::unique_ptr<AccountConfig>&& config)
     102             :     {
     103           0 :         std::lock_guard lock(configurationMutex_);
     104           0 :         config_ = std::move(config);
     105           0 :         loadConfig();
     106           0 :     }
     107             : 
     108             :     /**
     109             :      * Load the settings in this account.
     110             :      */
     111             :     virtual void loadConfig();
     112             : 
     113       37693 :     const AccountConfig& config() const
     114             :     {
     115       37693 :         if (config_)
     116       37688 :             return *config_;
     117             :         else
     118           0 :             throw std::runtime_error("Account doesn't have a configuration");
     119             :     }
     120             : 
     121         666 :     inline void editConfig(std::function<void(AccountConfig& config)>&& edit)
     122             :     {
     123         666 :         std::lock_guard lock(configurationMutex_);
     124         666 :         edit(*config_);
     125         666 :         saveConfig();
     126         666 :     }
     127             : 
     128             :     virtual void saveConfig() const;
     129             : 
     130         671 :     void setAccountDetails(const std::map<std::string, std::string>& details)
     131             :     {
     132         671 :         std::lock_guard lock(configurationMutex_);
     133         671 :         if (not config_)
     134         654 :             config_ = buildConfig();
     135         671 :         config_->fromMap(details);
     136         671 :         loadConfig();
     137         671 :         saveConfig();
     138         671 :     }
     139             : 
     140         357 :     std::map<std::string, std::string> getAccountDetails() const
     141             :     {
     142         357 :         std::lock_guard lock(configurationMutex_);
     143         714 :         return config().toMap();
     144         357 :     }
     145             : 
     146             :     virtual std::map<std::string, std::string> getVolatileAccountDetails() const;
     147             : 
     148             :     virtual std::string getFromUri() const = 0;
     149             : 
     150             :     /**
     151             :      * Get the account ID
     152             :      * @return constant account id
     153             :      */
     154       82681 :     inline const std::string& getAccountID() const { return accountID_; }
     155             : 
     156             :     virtual std::string_view getAccountType() const = 0;
     157             : 
     158        3194 :     const std::filesystem::path& getPath() const { return idPath_; }
     159             : 
     160             :     /**
     161             :      * Returns true if this is the IP2IP account
     162             :      */
     163        4406 :     virtual bool isIP2IP() const { return false; }
     164             : 
     165             :     /**
     166             :      * Register the account.
     167             :      * This should update the getRegistrationState() return value.
     168             :      */
     169             :     virtual void doRegister() = 0;
     170             : 
     171             :     /**
     172             :      * Unregister the account.
     173             :      * This should update the getRegistrationState() return value.
     174             :      */
     175             :     virtual void doUnregister(bool forceShutdownConnections = false) = 0;
     176             : 
     177           2 :     RegistrationState getRegistrationState() const { return registrationState_; }
     178             : 
     179             :     /**
     180             :      * Create a new outgoing call.
     181             :      *
     182             :      * @param toUrl The address to call
     183             :      * @param mediaList A list of media
     184             :      * @return The created call
     185             :      */
     186             :     virtual std::shared_ptr<Call> newOutgoingCall(std::string_view toUrl,
     187             :                                                   const std::vector<libjami::MediaMap>& mediaList)
     188             :         = 0;
     189             : 
     190             :     /**
     191             :      * If supported, send a text message from this account.
     192             :      * @return a token to query the message status
     193             :      */
     194           0 :     virtual uint64_t sendTextMessage(const std::string& /*to*/,
     195             :                                      const std::string& /*deviceId*/,
     196             :                                      const std::map<std::string, std::string>& /*payloads*/,
     197             :                                      uint64_t /*refreshToken*/ = 0,
     198             :                                      bool /*onlyConnected*/ = false)
     199             :     {
     200           0 :         return 0;
     201             :     }
     202             : 
     203           0 :     virtual void setIsComposing(const std::string& /*conversationUri*/, bool /*isWriting*/) {};
     204             : 
     205           0 :     virtual bool setMessageDisplayed(const std::string& /*conversationUri*/,
     206             :                                      const std::string& /*messageId*/,
     207             :                                      int /*status*/)
     208             :     {
     209           0 :         return false;
     210             :     };
     211             : 
     212           0 :     virtual std::vector<libjami::Message> getLastMessages(const uint64_t& /*base_timestamp*/)
     213             :     {
     214           0 :         return {};
     215             :     }
     216             : 
     217           0 :     virtual std::map<std::string, std::string> getNearbyPeers() const { return {}; }
     218             : 
     219             :     virtual void updateProfile(const std::string& /*displayName*/,  const std::string& /*avatar*/, const std::string& /*fileType*/, int32_t /*flag*/) = 0;
     220             : 
     221             :     std::map<std::string, std::string> getProfileVcard() const;
     222             : 
     223             :     /**
     224             :      * Return the status corresponding to the token.
     225             :      */
     226           0 :     virtual im::MessageStatus getMessageStatus(uint64_t /*id*/) const
     227             :     {
     228           0 :         return im::MessageStatus::UNKNOWN;
     229             :     }
     230             : 
     231           0 :     virtual bool cancelMessage(uint64_t /*id*/) { return false; }
     232             : 
     233           0 :     virtual bool setPushNotificationToken(const std::string& pushDeviceToken = "")
     234             :     {
     235           0 :         std::lock_guard lock(configurationMutex_);
     236           0 :         if (config_ && config_->deviceKey != pushDeviceToken) {
     237           0 :             config_->deviceKey = pushDeviceToken;
     238           0 :             saveConfig();
     239           0 :             return true;
     240             :         }
     241           0 :         return false;
     242           0 :     }
     243             : 
     244           0 :     virtual bool setPushNotificationTopic(const std::string& topic = "")
     245             :     {
     246           0 :         std::lock_guard lock(configurationMutex_);
     247           0 :         if (config_ && config_->notificationTopic != topic) {
     248           0 :             config_->notificationTopic = topic;
     249           0 :             saveConfig();
     250           0 :             return true;
     251             :         }
     252           0 :         return false;
     253           0 :     }
     254             : 
     255             :     virtual bool setPushNotificationConfig(const std::map<std::string, std::string>& data);
     256             : 
     257             :     /**
     258             :      * Tell if the account is enable or not.
     259             :      * @return true if enabled, false otherwise
     260             :      */
     261        1460 :     bool isEnabled() const { return config().enabled; }
     262             : 
     263         149 :     void setEnabled(bool enable)
     264             :     {
     265         149 :         config_->enabled = enable;
     266             :         // Update the UPnP controller to make sure it's in the correct state since this
     267             :         // depends on whether the account is enabled or not (in particular, we don't want
     268             :         // disabled accounts to generate UPnP activity).
     269         149 :         updateUpnpController();
     270         149 :     }
     271             : 
     272             :     /**
     273             :      * Tell if the account is activated
     274             :      * (can currently be used).
     275             :      */
     276           0 :     bool isActive() const noexcept { return active_; }
     277             : 
     278           0 :     void setActive(bool active) noexcept { active_ = active; }
     279             : 
     280        2222 :     bool isUsable() const { return config().enabled and active_; }
     281             : 
     282           7 :     void enableVideo(bool enable)
     283             :     {
     284           7 :         editConfig([&](AccountConfig& config) { config.videoEnabled = enable; });
     285           7 :     }
     286         507 :     bool isVideoEnabled() const { return config().videoEnabled; }
     287             : 
     288             :     /**
     289             :      * Set the registration state of the specified link
     290             :      * @param state The registration state of underlying VoIPLink
     291             :      */
     292             :     virtual void setRegistrationState(RegistrationState state,
     293             :                                       int detail_code = 0,
     294             :                                       const std::string& detail_str = {});
     295             : 
     296       10308 :     const std::string& getUsername() const { return config().username; }
     297             :     const std::string& getHostname() const { return config().hostname; }
     298             :     const std::string& getAlias() const { return config().alias; }
     299             : 
     300             :     static std::vector<unsigned> getDefaultCodecsId();
     301             :     static std::map<std::string, std::string> getDefaultCodecDetails(const unsigned& codecId);
     302             : 
     303             :     /* Accessor to data structures
     304             :      * @return The list that reflects the user's choice
     305             :      */
     306             :     std::vector<unsigned> getActiveCodecs(MediaType mediaType = MEDIA_ALL) const;
     307             :     bool hasActiveCodec(MediaType mediaType) const;
     308             : 
     309             :     /**
     310             :      * Update both the codec order structure and the codec string used for
     311             :      * SDP offer and configuration respectively
     312             :      */
     313             :     virtual void setActiveCodecs(const std::vector<unsigned>& list);
     314             :     std::shared_ptr<SystemCodecInfo> searchCodecById(unsigned codecId, MediaType mediaType);
     315             :     std::vector<std::shared_ptr<SystemCodecInfo>> getActiveAccountCodecInfoList(
     316             :         MediaType mediaType) const;
     317             :     std::shared_ptr<SystemCodecInfo> searchCodecByPayload(unsigned payload, MediaType mediaType);
     318             : 
     319          60 :     std::filesystem::path getRingtonePath() const { return ringtonePath_; }
     320          60 :     bool getRingtoneEnabled() const { return config().ringtoneEnabled; }
     321         531 :     std::string getDisplayName() const { return config().displayName; }
     322             :     std::string getMailBox() const { return config().mailbox; }
     323             : 
     324         214 :     bool isRendezVous() const { return config().isRendezVous; }
     325         104 :     bool isAutoAnswerEnabled() const { return config().autoAnswerEnabled; }
     326          36 :     bool isDenySecondCallEnabled() const
     327             :     {
     328          36 :         return config().denySecondCallEnabled;
     329             :     }
     330          12 :     bool isReadReceiptEnabled() const { return config().sendReadReceipt; }
     331          30 :     bool isComposingEnabled() const { return config().sendComposing; }
     332             : 
     333             :     /**
     334             :      * returns whether or not UPnP is enabled and active
     335             :      * ie: if it is able to make port mappings
     336             :      */
     337             :     bool getUPnPActive() const;
     338             : 
     339             :     /**
     340             :      * Get the UPnP IP (external router) address.
     341             :      * If use UPnP is set to false, the address will be empty.
     342             :      */
     343             :     dhtnet::IpAddr getUPnPIpAddress() const;
     344             : 
     345             :     /**
     346             :      * Random generator engine
     347             :      * Logical account state shall never rely on the state of the random generator.
     348             :      */
     349             :     mutable std::mt19937_64 rand;
     350             : 
     351             :     /**
     352             :      * Inform the account that the network status has changed.
     353             :      */
     354           0 :     virtual void connectivityChanged() {};
     355             : 
     356           0 :     virtual bool handleMessage(const std::shared_ptr<dht::crypto::Certificate>& /*cert*/,
     357             :                                const std::string& /*from*/,
     358             :                                const std::pair<std::string, std::string>& /*message*/)
     359             :     {
     360           0 :         return false;
     361             :     };
     362             : 
     363             :     /**
     364             :      * Helper function used to load the default codec order from the codec factory
     365             :      */
     366             :     void loadDefaultCodecs();
     367             : 
     368             :     void setCodecActive(unsigned codecId);
     369             : 
     370             :     void setCodecInactive(unsigned codecId);
     371             : 
     372             :     /**
     373             :      * Get the user-agent
     374             :      */
     375             :     const std::string& getUserAgentName();
     376             : 
     377          69 :     std::set<std::string> getDefaultModerators() const { return config().defaultModerators; }
     378             : 
     379             :     void addDefaultModerator(const std::string& peerURI);
     380             :     void removeDefaultModerator(const std::string& peerURI);
     381             : 
     382          69 :     bool isLocalModeratorsEnabled() const { return config().localModeratorsEnabled; }
     383          69 :     bool isAllModerators() const { return config().allModeratorsEnabled; }
     384             : 
     385             :     // Enable/disable ICE for media
     386         395 :     bool isIceForMediaEnabled() const { return iceForMediaEnabled_; }
     387           3 :     void enableIceForMedia(bool enable) { iceForMediaEnabled_ = enable; }
     388             : 
     389             :     // Enable/disable generation of empty offers
     390          10 :     bool isEmptyOffersEnabled() const { return false; }
     391             : 
     392             :     // Check if a Daemon version (typically peer's version) satisfies the
     393             :     // minimum required version. This check is typically used to disable a
     394             :     // feature if it's not backward compatible with the peer's version.
     395             :     static bool meetMinimumRequiredVersion(const std::vector<unsigned>& jamiVersion,
     396             :                                            const std::vector<unsigned>& minRequiredVersion);
     397             : 
     398             :     // Enable/disable compliancy with RFC-5245 for component IDs format.
     399             :     // The ICE component IDs are enumerated relative to the SDP session,
     400             :     // i.e., starts from 1 and incremented for each component.
     401             :     // However, RFC-5245 requires that the ICE component IDs are enumerated
     402             :     // relative to the media stream, e.g., component IDs 1 and 2 for audio,
     403             :     // and component IDs 1 and 2 for video. This non-conformity can cause
     404             :     // inter-operability issues.
     405             :     // When the compliancy feature is enabled, the component ID in the
     406             :     // generated SDP will be compliant to RFC-5245. This feature should be
     407             :     // enabled only when the peer is compliant to RFC-5245 as well.
     408             :     // The current version is able to correctly parse both formats.
     409             :     // This feature is needed for backward compatiblity, and should be removed
     410             :     // once the  backward compatibility is no more required.
     411         227 :     bool isIceCompIdRfc5245Compliant() const { return iceCompIdRfc5245Compliant_; }
     412           4 :     void enableIceCompIdRfc5245Compliance(bool enable) { iceCompIdRfc5245Compliant_ = enable; }
     413           0 :     void enableAutoLoadConversations(bool enable) { autoLoadConversations_ = enable; }
     414             : 
     415         704 :     std::shared_ptr<Call> getCall(const std::string& callId) const
     416             :     {
     417         704 :         return callSet_.getCall(callId);
     418             :     }
     419           1 :     std::vector<std::string> getCallList() const { return callSet_.getCallIds(); }
     420         104 :     std::shared_ptr<Conference> getConference(const std::string& confId) const
     421             :     {
     422         104 :         return callSet_.getConference(confId);
     423             :     }
     424           4 :     std::vector<std::string> getConferenceList() const { return callSet_.getConferenceIds(); }
     425         395 :     void attach(const std::shared_ptr<Call>& call) { callSet_.add(call); }
     426         407 :     bool detach(const std::shared_ptr<Call>& call) { return callSet_.remove(call); }
     427          38 :     void attach(const std::shared_ptr<Conference>& conf) { callSet_.add(conf); }
     428          59 :     bool removeConference(const std::string& confId)
     429             :     {
     430          59 :         auto result = callSet_.removeConference(confId);
     431          59 :         if (result)
     432          35 :             emitSignal<libjami::CallSignal::ConferenceRemoved>(getAccountID(), confId);
     433          59 :         return result;
     434             :     }
     435             : 
     436             : public:
     437             :     // virtual methods that has to be implemented by concrete classes
     438             :     /**
     439             :      * This method is called to request removal of possible account traces on the system,
     440             :      * like internal account setup files.
     441             :      */
     442         654 :     virtual void flush() {/* nothing to do here - overload */};
     443             : 
     444             : private:
     445             :     NON_COPYABLE(Account);
     446             : 
     447             :     /**
     448             :      * Set of calls attached to the account.
     449             :      */
     450             :     CallSet callSet_;
     451             : 
     452             : protected:
     453             :     virtual void updateUpnpController();
     454             : 
     455             :     std::unique_ptr<AccountConfig> config_ {};
     456             : 
     457             :     friend class ConfigurationTest;
     458             : 
     459             :     static const std::string DEFAULT_USER_AGENT;
     460             : 
     461             :     static std::string mapStateNumberToString(RegistrationState state);
     462             : 
     463             :     /**
     464             :      * Build the user-agent string
     465             :      */
     466             :     static std::string getDefaultUserAgent();
     467             : 
     468             :     /**
     469             :      * Account ID are assign in constructor and shall not changed
     470             :      */
     471             :     const std::string accountID_;
     472             : 
     473             :     mutable std::recursive_mutex configurationMutex_ {};
     474             : 
     475             :     /**
     476             :      * Tells if the account is active now.
     477             :      * This allows doRegister to be called.
     478             :      * When an account is unactivated, doUnregister must be called.
     479             :      */
     480             :     bool active_ {true};
     481             : 
     482             :     /*
     483             :      * The general, protocol neutral registration
     484             :      * state of the account
     485             :      */
     486             :     RegistrationState registrationState_ {RegistrationState::UNLOADED};
     487             : 
     488             :     /**
     489             :      * Vector containing all system codecs (with default parameters)
     490             :      */
     491             :     std::shared_ptr<SystemCodecContainer> systemCodecContainer_;
     492             :     /**
     493             :      * Vector containing all account codecs (set of system codecs with custom parameters)
     494             :      */
     495             :     std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecInfoList_;
     496             : 
     497             :     /**
     498             :      * path to account
     499             :      */
     500             :     std::filesystem::path idPath_ {};
     501             : 
     502             :     /**
     503             :      * Ringtone .au file used for this account
     504             :      */
     505             :     std::filesystem::path ringtonePath_;
     506             : 
     507             :     /**
     508             :      * UPnP IGD controller and the mutex to access it
     509             :      */
     510             :     mutable std::mutex upnp_mtx {};
     511             :     std::shared_ptr<dhtnet::upnp::Controller> upnpCtrl_;
     512             : 
     513             :     bool iceForMediaEnabled_ {true};
     514             :     bool iceCompIdRfc5245Compliant_ {false};
     515             :     /**
     516             :      * Auto load conversations when creatinf convModule()
     517             :      */
     518             :     bool autoLoadConversations_ {true};
     519             : 
     520             :     /**
     521             :      * private account codec searching functions
     522             :      */
     523             :     std::shared_ptr<SystemCodecInfo> searchCodecByName(const std::string& name, MediaType mediaType);
     524             :     std::vector<unsigned> getAccountCodecInfoIdList(MediaType mediaType) const;
     525             :     void setAllCodecsActive(MediaType mediaType, bool active);
     526             :     void sortCodec();
     527             : };
     528             : 
     529             : static inline std::ostream&
     530          10 : operator<<(std::ostream& os, const Account& acc)
     531             : {
     532          10 :     os << "[Account " << acc.getAccountID() << "] ";
     533          10 :     return os;
     534             : }
     535             : 
     536             : } // namespace jami

Generated by: LCOV version 1.14