LCOV - code coverage report
Current view: top level - src - account.h (source / functions) Coverage Total Hit
Test: jami-coverage-filtered.info Lines: 61.5 % 104 64
Test Date: 2026-06-13 09:18:46 Functions: 70.9 % 55 39

            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        47626 :     const AccountConfig& config() const
     109              :     {
     110        47626 :         if (config_)
     111        47634 :             return *config_;
     112              :         else
     113            0 :             throw std::runtime_error("Account doesn't have a configuration");
     114              :     }
     115              : 
     116          813 :     inline void editConfig(std::function<void(AccountConfig& config)>&& edit)
     117              :     {
     118          813 :         std::lock_guard lock(configurationMutex_);
     119          813 :         edit(*config_);
     120          813 :         saveConfig();
     121          813 :     }
     122              : 
     123              :     virtual void saveConfig() const;
     124              : 
     125          817 :     void setAccountDetails(const std::map<std::string, std::string>& details)
     126              :     {
     127          817 :         std::lock_guard lock(configurationMutex_);
     128          817 :         if (not config_)
     129          797 :             config_ = buildConfig();
     130          817 :         config_->fromMap(details);
     131          817 :         loadConfig();
     132          817 :         saveConfig();
     133          817 :     }
     134              : 
     135          333 :     std::map<std::string, std::string> getAccountDetails() const
     136              :     {
     137          333 :         std::lock_guard lock(configurationMutex_);
     138          666 :         return config().toMap();
     139          333 :     }
     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       111757 :     inline const std::string& getAccountID() const { return accountID_; }
     150              : 
     151              :     virtual std::string_view getAccountType() const = 0;
     152              : 
     153         6661 :     const std::filesystem::path& getPath() const { return idPath_; }
     154              : 
     155              :     /**
     156              :      * Returns true if this is the IP2IP account
     157              :      */
     158         4604 :     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              :                                int32_t /*flag*/)
     215              :         = 0;
     216              : 
     217              :     vCard::utils::VCardData getProfileVcard() const;
     218              : 
     219              :     /**
     220              :      * Return the status corresponding to the token.
     221              :      */
     222            0 :     virtual im::MessageStatus getMessageStatus(uint64_t /*id*/) const { return im::MessageStatus::UNKNOWN; }
     223              : 
     224            0 :     virtual bool setPushNotificationToken(const std::string& pushDeviceToken = "")
     225              :     {
     226            0 :         std::lock_guard lock(configurationMutex_);
     227            0 :         if (config_ && config_->deviceKey != pushDeviceToken) {
     228            0 :             config_->deviceKey = pushDeviceToken;
     229            0 :             saveConfig();
     230            0 :             return true;
     231              :         }
     232            0 :         return false;
     233            0 :     }
     234              : 
     235            0 :     virtual bool setPushNotificationTopic(const std::string& topic = "")
     236              :     {
     237            0 :         std::lock_guard lock(configurationMutex_);
     238            0 :         if (config_ && config_->notificationTopic != topic) {
     239            0 :             config_->notificationTopic = topic;
     240            0 :             saveConfig();
     241            0 :             return true;
     242              :         }
     243            0 :         return false;
     244            0 :     }
     245              : 
     246              :     virtual bool setPushNotificationConfig(const std::map<std::string, std::string>& data);
     247              : 
     248              :     /**
     249              :      * Tell if the account is enable or not.
     250              :      * @return true if enabled, false otherwise
     251              :      */
     252         1821 :     bool isEnabled() const { return config().enabled; }
     253              : 
     254          212 :     void setEnabled(bool enable)
     255              :     {
     256          212 :         config_->enabled = enable;
     257              :         // Update the UPnP controller to make sure it's in the correct state since this
     258              :         // depends on whether the account is enabled or not (in particular, we don't want
     259              :         // disabled accounts to generate UPnP activity).
     260          212 :         updateUpnpController();
     261          212 :     }
     262              : 
     263              :     /**
     264              :      * Tell if the account is activated
     265              :      * (can currently be used).
     266              :      */
     267            0 :     bool isActive() const noexcept { return active_; }
     268              : 
     269            0 :     void setActive(bool active) noexcept { active_ = active; }
     270              : 
     271         2748 :     bool isUsable() const { return config().enabled and active_; }
     272              : 
     273            7 :     void enableVideo(bool enable)
     274              :     {
     275            7 :         editConfig([&](AccountConfig& config) { config.videoEnabled = enable; });
     276            7 :     }
     277          497 :     bool isVideoEnabled() const { return config().videoEnabled; }
     278              : 
     279              :     /**
     280              :      * Set the registration state of the specified link
     281              :      * @param state The registration state of underlying VoIPLink
     282              :      */
     283              :     virtual void setRegistrationState(RegistrationState state, int detail_code = 0, const std::string& detail_str = {});
     284              : 
     285        13996 :     const std::string& getUsername() const { return config().username; }
     286              :     const std::string& getHostname() const { return config().hostname; }
     287              :     const std::string& getAlias() const { return config().alias; }
     288              : 
     289              :     static std::vector<unsigned> getDefaultCodecsId();
     290              :     static std::map<std::string, std::string> getDefaultCodecDetails(const unsigned& codecId);
     291              : 
     292              :     /* Accessor to data structures
     293              :      * @return The list that reflects the user's choice
     294              :      */
     295              :     std::vector<unsigned> getActiveCodecs(MediaType mediaType = MEDIA_ALL) const;
     296              :     bool hasActiveCodec(MediaType mediaType) const;
     297              : 
     298              :     /**
     299              :      * Update both the codec order structure and the codec string used for
     300              :      * SDP offer and configuration respectively
     301              :      */
     302              :     virtual void setActiveCodecs(const std::vector<unsigned>& list);
     303              :     std::shared_ptr<SystemCodecInfo> searchCodecById(unsigned codecId, MediaType mediaType);
     304              :     std::vector<std::shared_ptr<SystemCodecInfo>> getActiveAccountCodecInfoList(MediaType mediaType) const;
     305              :     std::shared_ptr<SystemCodecInfo> searchCodecByPayload(unsigned payload, MediaType mediaType);
     306              : 
     307           55 :     std::filesystem::path getRingtonePath() const { return ringtonePath_; }
     308           55 :     bool getRingtoneEnabled() const { return config().ringtoneEnabled; }
     309          720 :     std::string getDisplayName() const { return config().displayName; }
     310              :     std::string getMailBox() const { return config().mailbox; }
     311              : 
     312          200 :     bool isRendezVous() const { return config().isRendezVous; }
     313           98 :     bool isAutoAnswerEnabled() const { return config().autoAnswerEnabled; }
     314           36 :     bool isDenySecondCallEnabled() const { return config().denySecondCallEnabled; }
     315           17 :     bool isReadReceiptEnabled() const { return config().sendReadReceipt; }
     316           28 :     bool isComposingEnabled() const { return config().sendComposing; }
     317              : 
     318              :     /**
     319              :      * returns whether or not UPnP is enabled and active
     320              :      * ie: if it is able to make port mappings
     321              :      */
     322              :     bool getUPnPActive() const;
     323              : 
     324              :     /**
     325              :      * Get the UPnP IP (external router) address.
     326              :      * If use UPnP is set to false, the address will be empty.
     327              :      */
     328              :     dhtnet::IpAddr getUPnPIpAddress() const;
     329              : 
     330              :     /**
     331              :      * Random generator engine
     332              :      * Logical account state shall never rely on the state of the random generator.
     333              :      */
     334              :     mutable std::mt19937_64 rand;
     335              : 
     336              :     /**
     337              :      * Inform the account that the network status has changed.
     338              :      */
     339            0 :     virtual void connectivityChanged() {};
     340              : 
     341            0 :     virtual bool handleMessage(const std::shared_ptr<dht::crypto::Certificate>& /*cert*/,
     342              :                                const std::string& /*from*/,
     343              :                                const std::pair<std::string, std::string>& /*message*/)
     344              :     {
     345            0 :         return false;
     346              :     };
     347              : 
     348              :     /**
     349              :      * Helper function used to load the default codec order from the codec factory
     350              :      */
     351              :     void loadDefaultCodecs();
     352              : 
     353              :     void setCodecActive(unsigned codecId);
     354              : 
     355              :     void setCodecInactive(unsigned codecId);
     356              : 
     357              :     /**
     358              :      * Get the user-agent
     359              :      */
     360              :     const std::string& getUserAgentName();
     361              : 
     362           68 :     std::set<std::string> getDefaultModerators() const { return config().defaultModerators; }
     363              : 
     364              :     void addDefaultModerator(const std::string& peerURI);
     365              :     void removeDefaultModerator(const std::string& peerURI);
     366              : 
     367           68 :     bool isLocalModeratorsEnabled() const { return config().localModeratorsEnabled; }
     368           68 :     bool isAllModerators() const { return config().allModeratorsEnabled; }
     369              : 
     370              :     // Enable/disable ICE for media
     371          371 :     bool isIceForMediaEnabled() const { return iceForMediaEnabled_; }
     372            3 :     void enableIceForMedia(bool enable) { iceForMediaEnabled_ = enable; }
     373              : 
     374              :     // Enable/disable generation of empty offers
     375           10 :     bool isEmptyOffersEnabled() const { return false; }
     376              : 
     377              :     // Check if a Daemon version (typically peer's version) satisfies the
     378              :     // minimum required version. This check is typically used to disable a
     379              :     // feature if it's not backward compatible with the peer's version.
     380              :     static bool meetMinimumRequiredVersion(const std::vector<unsigned>& jamiVersion,
     381              :                                            const std::vector<unsigned>& minRequiredVersion);
     382              : 
     383              :     // Enable/disable compliancy with RFC-5245 for component IDs format.
     384              :     // The ICE component IDs are enumerated relative to the SDP session,
     385              :     // i.e., starts from 1 and incremented for each component.
     386              :     // However, RFC-5245 requires that the ICE component IDs are enumerated
     387              :     // relative to the media stream, e.g., component IDs 1 and 2 for audio,
     388              :     // and component IDs 1 and 2 for video. This non-conformity can cause
     389              :     // inter-operability issues.
     390              :     // When the compliancy feature is enabled, the component ID in the
     391              :     // generated SDP will be compliant to RFC-5245. This feature should be
     392              :     // enabled only when the peer is compliant to RFC-5245 as well.
     393              :     // The current version is able to correctly parse both formats.
     394              :     // This feature is needed for backward compatiblity, and should be removed
     395              :     // once the  backward compatibility is no more required.
     396          225 :     bool isIceCompIdRfc5245Compliant() const { return iceCompIdRfc5245Compliant_; }
     397            4 :     void enableIceCompIdRfc5245Compliance(bool enable) { iceCompIdRfc5245Compliant_ = enable; }
     398            0 :     void enableAutoLoadConversations(bool enable) { autoLoadConversations_ = enable; }
     399              : 
     400          648 :     std::shared_ptr<Call> getCall(const std::string& callId) const { return callSet_.getCall(callId); }
     401            0 :     std::vector<std::string> getCallList() const { return callSet_.getCallIds(); }
     402           97 :     std::shared_ptr<Conference> getConference(const std::string& confId) const
     403              :     {
     404           97 :         return callSet_.getConference(confId);
     405              :     }
     406            4 :     std::vector<std::string> getConferenceList() const { return callSet_.getConferenceIds(); }
     407          371 :     void attach(const std::shared_ptr<Call>& call) { callSet_.add(call); }
     408          385 :     bool detach(const std::shared_ptr<Call>& call) { return callSet_.remove(call); }
     409           37 :     void attach(const std::shared_ptr<Conference>& conf) { callSet_.add(conf); }
     410           56 :     bool removeConference(const std::string& confId)
     411              :     {
     412           56 :         auto result = callSet_.removeConference(confId);
     413           56 :         if (result)
     414           33 :             emitSignal<libjami::CallSignal::ConferenceRemoved>(getAccountID(), confId);
     415           56 :         return result;
     416              :     }
     417              : 
     418              : public:
     419              :     // virtual methods that has to be implemented by concrete classes
     420              :     /**
     421              :      * This method is called to request removal of possible account traces on the system,
     422              :      * like internal account setup files.
     423              :      */
     424          797 :     virtual void flush() { /* nothing to do here - overload */ };
     425              : 
     426              : private:
     427              :     NON_COPYABLE(Account);
     428              : 
     429              :     /**
     430              :      * Set of calls attached to the account.
     431              :      */
     432              :     CallSet callSet_;
     433              : 
     434              : protected:
     435              :     virtual void updateUpnpController();
     436              : 
     437              :     std::unique_ptr<AccountConfig> config_ {};
     438              : 
     439              :     friend class ConfigurationTest;
     440              : 
     441              :     static const std::string DEFAULT_USER_AGENT;
     442              : 
     443              :     static std::string mapStateNumberToString(RegistrationState state);
     444              : 
     445              :     /**
     446              :      * Build the user-agent string
     447              :      */
     448              :     static std::string getDefaultUserAgent();
     449              : 
     450              :     /**
     451              :      * Account ID are assign in constructor and shall not changed
     452              :      */
     453              :     const std::string accountID_;
     454              : 
     455              :     mutable std::recursive_mutex configurationMutex_ {};
     456              : 
     457              :     /**
     458              :      * Tells if the account is active now.
     459              :      * This allows doRegister to be called.
     460              :      * When an account is unactivated, doUnregister must be called.
     461              :      */
     462              :     bool active_ {true};
     463              : 
     464              :     /*
     465              :      * The general, protocol neutral registration
     466              :      * state of the account
     467              :      */
     468              :     RegistrationState registrationState_ {RegistrationState::UNLOADED};
     469              : 
     470              :     /**
     471              :      * Vector containing all system codecs (with default parameters)
     472              :      */
     473              :     std::shared_ptr<SystemCodecContainer> systemCodecContainer_;
     474              :     /**
     475              :      * Vector containing all account codecs (set of system codecs with custom parameters)
     476              :      */
     477              :     std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecInfoList_;
     478              : 
     479              :     /**
     480              :      * path to account
     481              :      */
     482              :     std::filesystem::path idPath_ {};
     483              : 
     484              :     /**
     485              :      * Ringtone .au file used for this account
     486              :      */
     487              :     std::filesystem::path ringtonePath_;
     488              : 
     489              :     /**
     490              :      * UPnP IGD controller and the mutex to access it
     491              :      */
     492              :     mutable std::mutex upnp_mtx {};
     493              :     std::shared_ptr<dhtnet::upnp::Controller> upnpCtrl_;
     494              : 
     495              :     bool iceForMediaEnabled_ {true};
     496              :     bool iceCompIdRfc5245Compliant_ {false};
     497              :     /**
     498              :      * Auto load conversations when creatinf convModule()
     499              :      */
     500              :     bool autoLoadConversations_ {true};
     501              : 
     502              :     /**
     503              :      * private account codec searching functions
     504              :      */
     505              :     std::shared_ptr<SystemCodecInfo> searchCodecByName(const std::string& name, MediaType mediaType);
     506              :     std::vector<unsigned> getAccountCodecInfoIdList(MediaType mediaType) const;
     507              :     void setAllCodecsActive(MediaType mediaType, bool active);
     508              :     void sortCodec();
     509              : };
     510              : 
     511              : static inline std::ostream&
     512              : operator<<(std::ostream& os, const Account& acc)
     513              : {
     514              :     os << "[Account " << acc.getAccountID() << "] ";
     515              :     return os;
     516              : }
     517              : 
     518              : } // namespace jami
        

Generated by: LCOV version 2.0-1