LCOV - code coverage report
Current view: top level - src - account.h (source / functions) Hit Total Coverage
Test: jami-coverage-filtered.info Lines: 64 106 60.4 %
Date: 2024-04-19 19:18:04 Functions: 39 55 70.9 %

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

Generated by: LCOV version 1.14