LCOV - code coverage report
Current view: top level - src - account.h (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 62.5 % 104 65
Test Date: 2026-07-06 08:25:38 Functions: 72.7 % 55 40

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

Generated by: LCOV version 2.0-1