| /* |
| * Copyright (C) 2004-2021 Savoir-faire Linux Inc. |
| * |
| * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> |
| * Author: Yan Morin <yan.morin@savoirfairelinux.com> |
| * Author: Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> |
| * |
| * This program is free software; you can redistribute it and/or modify |
| * it under the terms of the GNU General Public License as published by |
| * the Free Software Foundation; either version 3 of the License, or |
| * (at your option) any later version. |
| * |
| * This program is distributed in the hope that it will be useful, |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
| * GNU General Public License for more details. |
| * |
| * You should have received a copy of the GNU General Public License |
| * along with this program; if not, write to the Free Software |
| * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
| */ |
| |
| #ifndef ACCOUNT_H |
| #define ACCOUNT_H |
| |
| #ifdef HAVE_CONFIG_H |
| #include "config.h" |
| #endif |
| |
| #include "client/ring_signal.h" |
| #include "configurationmanager_interface.h" |
| #include "noncopyable.h" |
| #include "config/serializable.h" |
| #include "registration_states.h" |
| #include "im/message_engine.h" |
| #include "ip_utils.h" |
| #include "media_codec.h" |
| #include "media/media_attribute.h" |
| #include "logger.h" |
| #include "compiler_intrinsics.h" // include the "UNUSED" macro |
| #include "call_set.h" |
| |
| #include <functional> |
| #include <string> |
| #include <vector> |
| #include <memory> |
| #include <map> |
| #include <set> |
| #include <random> |
| #include <stdexcept> |
| #include <atomic> |
| #include <mutex> |
| #include <chrono> |
| |
| namespace YAML { |
| class Emitter; |
| class Node; |
| } // namespace YAML |
| |
| namespace Json { |
| class Value; |
| } |
| |
| namespace jami { |
| static constexpr uint64_t JAMI_ID_MAX_VAL = 9007199254740992; |
| |
| namespace upnp { |
| class Controller; |
| } // namespace upnp |
| |
| class Call; |
| class SystemCodecContainer; |
| struct IceTransportOptions; |
| |
| class VoipLinkException : public std::runtime_error |
| { |
| public: |
| VoipLinkException(const std::string& str = "") |
| : std::runtime_error("VoipLinkException occurred: " + str) |
| {} |
| }; |
| |
| /** |
| * @file account.h |
| * @brief Interface to protocol account (ex: SIPAccount) |
| * It can be enable on loading or activate after. |
| * It contains account, configuration, VoIP Link and Calls (inside the VoIPLink) |
| */ |
| |
| class Account : public Serializable, public std::enable_shared_from_this<Account> |
| { |
| public: |
| Account(const std::string& accountID); |
| |
| /** |
| * Virtual destructor |
| */ |
| virtual ~Account(); |
| |
| /** |
| * Free all ressources related to this account. |
| * ***Current calls using this account are HANG-UP*** |
| */ |
| void hangupCalls(); |
| |
| virtual void setAccountDetails(const std::map<std::string, std::string>& details); |
| |
| virtual std::map<std::string, std::string> getAccountDetails() const; |
| |
| virtual std::map<std::string, std::string> getVolatileAccountDetails() const; |
| |
| virtual std::string getFromUri() const = 0; |
| |
| /** |
| * Load the settings for this account. |
| */ |
| virtual void loadConfig() = 0; |
| |
| virtual void serialize(YAML::Emitter& out) const; |
| virtual void unserialize(const YAML::Node& node); |
| |
| /** |
| * Get the account ID |
| * @return constant account id |
| */ |
| const std::string& getAccountID() const { return accountID_; } |
| |
| virtual const char* getAccountType() const = 0; |
| |
| /** |
| * Returns true if this is the IP2IP account |
| */ |
| virtual bool isIP2IP() const { return false; } |
| |
| /** |
| * Register the account. |
| * This should update the getRegistrationState() return value. |
| */ |
| virtual void doRegister() = 0; |
| |
| /** |
| * Unregister the account. |
| * This should update the getRegistrationState() return value. |
| */ |
| virtual void doUnregister(std::function<void(bool)> cb = std::function<void(bool)>()) = 0; |
| |
| RegistrationState getRegistrationState() const { return registrationState_; } |
| |
| /** |
| * Create a new outgoing call. |
| * |
| * @param toUrl The address to call |
| * @param mediaList A list of media |
| * @return The created call |
| */ |
| virtual std::shared_ptr<Call> newOutgoingCall(std::string_view toUrl, |
| const std::vector<DRing::MediaMap>& mediaList) |
| = 0; |
| |
| /** |
| * If supported, send a text message from this account. |
| * @return a token to query the message status |
| */ |
| virtual uint64_t sendTextMessage(const std::string& /*to*/, |
| const std::map<std::string, std::string>& /*payloads*/) |
| { |
| return 0; |
| } |
| |
| virtual void setIsComposing(const std::string& /*conversationUri*/, bool /*isWriting*/) {}; |
| |
| virtual bool setMessageDisplayed(const std::string& /*conversationUri*/, |
| const std::string& /*messageId*/, |
| int /*status*/) |
| { |
| return false; |
| }; |
| |
| virtual std::vector<DRing::Message> getLastMessages(const uint64_t& /*base_timestamp*/) |
| { |
| return {}; |
| } |
| |
| virtual std::map<std::string, std::string> getNearbyPeers() const { return {}; } |
| |
| /** |
| * Return the status corresponding to the token. |
| */ |
| virtual im::MessageStatus getMessageStatus(uint64_t /*id*/) const |
| { |
| return im::MessageStatus::UNKNOWN; |
| } |
| |
| virtual bool cancelMessage(uint64_t /*id*/) { return false; } |
| |
| virtual void setPushNotificationToken(const std::string& pushDeviceToken = "") |
| { |
| deviceKey_ = pushDeviceToken; |
| } |
| |
| /** |
| * Tell if the account is enable or not. |
| * @return true if enabled, false otherwise |
| */ |
| bool isEnabled() const noexcept { return enabled_; } |
| |
| void setEnabled(bool enable) noexcept { enabled_ = enable; } |
| |
| /** |
| * Tell if the account is activated |
| * (can currently be used). |
| */ |
| bool isActive() const noexcept { return active_; } |
| |
| void setActive(bool active) noexcept { active_ = active; } |
| |
| bool isUsable() const noexcept { return enabled_ and active_; } |
| |
| void enableVideo(bool enable) { videoEnabled_ = enable; } |
| bool isVideoEnabled() const noexcept { return videoEnabled_; } |
| |
| /** |
| * Set the registration state of the specified link |
| * @param state The registration state of underlying VoIPLink |
| */ |
| virtual void setRegistrationState(RegistrationState state, |
| unsigned detail_code = 0, |
| const std::string& detail_str = {}); |
| |
| /* They should be treated like macro definitions by the C++ compiler */ |
| const std::string& getUsername() const { return username_; } |
| |
| const std::string& getHostname() const { return hostname_; } |
| void setHostname(const std::string& hostname) { hostname_ = hostname; } |
| |
| const std::string& getAlias() const { return alias_; } |
| |
| void setAlias(const std::string& alias) { alias_ = alias; } |
| |
| static std::vector<unsigned> getDefaultCodecsId(); |
| static std::map<std::string, std::string> getDefaultCodecDetails(const unsigned& codecId); |
| |
| /* Accessor to data structures |
| * @return The list that reflects the user's choice |
| */ |
| std::vector<unsigned> getActiveCodecs(MediaType mediaType = MEDIA_ALL) const; |
| bool hasActiveCodec(MediaType mediaType) const; |
| |
| /** |
| * Update both the codec order structure and the codec string used for |
| * SDP offer and configuration respectively |
| */ |
| virtual void setActiveCodecs(const std::vector<unsigned>& list); |
| std::shared_ptr<AccountCodecInfo> searchCodecById(unsigned codecId, MediaType mediaType); |
| std::vector<std::shared_ptr<AccountCodecInfo>> getActiveAccountCodecInfoList( |
| MediaType mediaType) const; |
| std::shared_ptr<AccountCodecInfo> searchCodecByPayload(unsigned payload, MediaType mediaType); |
| |
| std::string getRingtonePath() const { return ringtonePath_; } |
| |
| void setRingtonePath(const std::string& path) { ringtonePath_ = path; } |
| |
| bool getRingtoneEnabled() const { return ringtoneEnabled_; } |
| void setRingtoneEnabled(bool enable) { ringtoneEnabled_ = enable; } |
| |
| std::string getDisplayName() const { return displayName_; } |
| void setDisplayName(const std::string& name) { displayName_ = name; } |
| |
| std::string getMailBox() const { return mailBox_; } |
| |
| void setMailBox(const std::string& mb) { mailBox_ = mb; } |
| |
| bool isRendezVous() const { return isRendezVous_; } |
| |
| bool isAutoAnswerEnabled() const { return autoAnswerEnabled_; } |
| |
| bool isReadReceiptEnabled() const { return sendReadReceipt_; } |
| |
| static const char* const VIDEO_CODEC_ENABLED; |
| static const char* const VIDEO_CODEC_NAME; |
| static const char* const VIDEO_CODEC_PARAMETERS; |
| static const char* const VIDEO_CODEC_BITRATE; |
| |
| /** |
| * returns whether or not UPnP is enabled and active |
| * ie: if it is able to make port mappings |
| */ |
| bool getUPnPActive() const; |
| |
| /** |
| * Get the UPnP IP (external router) address. |
| * If use UPnP is set to false, the address will be empty. |
| */ |
| IpAddr getUPnPIpAddress() const; |
| |
| /** |
| * Random generator engine |
| * Logical account state shall never rely on the state of the random generator. |
| */ |
| mutable std::mt19937_64 rand; |
| |
| /** |
| * Inform the account that the network status has changed. |
| */ |
| virtual void connectivityChanged() {}; |
| |
| virtual bool handleMessage(const std::string& /*from*/, |
| const std::pair<std::string, std::string>& /*message*/) |
| { |
| return false; |
| }; |
| |
| /** |
| * Helper function used to load the default codec order from the codec factory |
| */ |
| void loadDefaultCodecs(); |
| |
| void setCodecActive(unsigned codecId); |
| |
| void setCodecInactive(unsigned codecId); |
| |
| std::vector<unsigned> convertIdToAVId(const std::vector<unsigned>& list); |
| |
| /** |
| * Get the user-agent |
| */ |
| const std::string& getUserAgentName(); |
| |
| std::set<std::string> getDefaultModerators() const { return defaultModerators_; } |
| |
| void addDefaultModerator(const std::string& peerURI); |
| void removeDefaultModerator(const std::string& peerURI); |
| |
| bool isLocalModeratorsEnabled() const { return localModeratorsEnabled_; } |
| void enableLocalModerators(bool isModEnabled) { localModeratorsEnabled_ = isModEnabled; } |
| bool isAllModerators() const { return allModeratorsEnabled_; } |
| void setAllModerators(bool isAllModeratorEnabled) |
| { |
| allModeratorsEnabled_ = isAllModeratorEnabled; |
| } |
| |
| // Enable/disable ICE for media |
| bool isIceForMediaEnabled() const { return iceForMediaEnabled_; } |
| void enableIceForMedia(bool enable) { iceForMediaEnabled_ = enable; } |
| |
| // Enable/disable generation of empty offers |
| bool isEmptyOffersEnabled() const { return emptyOffersEnabled_; } |
| void enableEmptyOffers(bool enable) { emptyOffersEnabled_ = enable; } |
| |
| // Check if a Daemon version (typically peer's version) satisfies the |
| // minimum required version. This check is typically used to disable a |
| // feature if it's not backward compatible with the peer's version. |
| static bool meetMinimumRequiredVersion(const std::vector<unsigned>& jamiVersion, |
| const std::vector<unsigned>& minRequiredVersion); |
| |
| // Enable/disable compliancy with RFC-5245 for component IDs format. |
| // The ICE component IDs are enumerated relative to the SDP session, |
| // i.e., starts from 1 and incremented for each component. |
| // However, RFC-5245 requires that the ICE component IDs are enumerated |
| // relative to the media stream, e.g., component IDs 1 and 2 for audio, |
| // and component IDs 1 and 2 for video. This non-conformity can cause |
| // inter-operability issues. |
| // When the compliancy feature is enabled, the component ID in the |
| // generated SDP will be compliant to RFC-5245. This feature should be |
| // enabled only when the peer is compliant to RFC-5245 as well. |
| // The current version is able to correctly parse both formats. |
| // This feature is needed for backward compatiblity, and should be removed |
| // once the backward compatibility is no more required. |
| bool isIceCompIdRfc5245Compliant() const { return iceCompIdRfc5245Compliant_; } |
| void enableIceCompIdRfc5245Compliance(bool enable) { iceCompIdRfc5245Compliant_ = enable; } |
| |
| std::shared_ptr<Call> getCall(const std::string& callId) const |
| { |
| return callSet_.getCall(callId); |
| } |
| std::vector<std::string> getCallList() const { return callSet_.getCallIds(); } |
| std::shared_ptr<Conference> getConference(const std::string& confId) const |
| { |
| return callSet_.getConference(confId); |
| } |
| std::vector<std::string> getConferenceList() const { return callSet_.getConferenceIds(); } |
| void attach(const std::shared_ptr<Call>& call) { callSet_.add(call); } |
| bool detach(const std::shared_ptr<Call>& call) { return callSet_.remove(call); } |
| void attach(const std::shared_ptr<Conference>& conf) { callSet_.add(conf); } |
| bool removeConference(const std::string& confId) |
| { |
| auto result = callSet_.removeConference(confId); |
| if (result) |
| emitSignal<DRing::CallSignal::ConferenceRemoved>(getAccountID(), confId); |
| return result; |
| } |
| |
| public: |
| // virtual methods that has to be implemented by concrete classes |
| /** |
| * This method is called to request removal of possible account traces on the system, |
| * like internal account setup files. |
| */ |
| virtual void flush() {/* nothing to do here - overload */}; |
| |
| private: |
| NON_COPYABLE(Account); |
| |
| /** |
| * Set of calls attached to the account. |
| */ |
| CallSet callSet_; |
| |
| protected: |
| void updateUpnpController(); |
| |
| static void parseString(const std::map<std::string, std::string>& details, |
| const char* key, |
| std::string& s); |
| static void parseBool(const std::map<std::string, std::string>& details, |
| const char* key, |
| bool& b); |
| static void parsePath(const std::map<std::string, std::string>& details, |
| const char* key, |
| std::string& s, |
| const std::string& base); |
| |
| template<class T> |
| static inline void parseInt(const std::map<std::string, std::string>& details, |
| const char* key, |
| T& i) |
| { |
| const auto& iter = details.find(key); |
| if (iter == details.end()) { |
| JAMI_ERR("Couldn't find key \"%s\"", key); |
| return; |
| } |
| i = atoi(iter->second.c_str()); |
| } |
| |
| friend class ConfigurationTest; |
| |
| // General configuration keys for accounts |
| static const char* const ALL_CODECS_KEY; |
| static const char* const RINGTONE_PATH_KEY; |
| static const char* const RINGTONE_ENABLED_KEY; |
| static const char* const VIDEO_ENABLED_KEY; |
| static const char* const DISPLAY_NAME_KEY; |
| static const char* const ALIAS_KEY; |
| static const char* const TYPE_KEY; |
| static const char* const ID_KEY; |
| static const char* const USERNAME_KEY; |
| static const char* const AUTHENTICATION_USERNAME_KEY; |
| static const char* const PASSWORD_KEY; |
| static const char* const HOSTNAME_KEY; |
| static const char* const ACCOUNT_ENABLE_KEY; |
| static const char* const ACCOUNT_AUTOANSWER_KEY; |
| static const char* const ACCOUNT_READRECEIPT_KEY; |
| static const char* const ACCOUNT_ISRENDEZVOUS_KEY; |
| static const char* const ACCOUNT_ACTIVE_CALL_LIMIT_KEY; |
| static const char* const MAILBOX_KEY; |
| static const char* const USER_AGENT_KEY; |
| static const char* const HAS_CUSTOM_USER_AGENT_KEY; |
| static const char* const PRESENCE_MODULE_ENABLED_KEY; |
| static const char* const UPNP_ENABLED_KEY; |
| static const char* const PROXY_ENABLED_KEY; |
| static const char* const PROXY_SERVER_KEY; |
| static const char* const PROXY_PUSH_TOKEN_KEY; |
| static const char* const ACTIVE_CODEC_KEY; |
| static const char* const DEFAULT_MODERATORS_KEY; |
| static const char* const LOCAL_MODERATORS_ENABLED_KEY; |
| static const char* const ALL_MODERATORS_ENABLED_KEY; |
| |
| static const std::string DEFAULT_USER_AGENT; |
| |
| static std::string mapStateNumberToString(RegistrationState state); |
| |
| /** |
| * Build the user-agent string |
| */ |
| static std::string setDefaultUserAgent(); |
| |
| /** |
| * Account ID are assign in constructor and shall not changed |
| */ |
| const std::string accountID_; |
| |
| mutable std::recursive_mutex configurationMutex_ {}; |
| |
| /** |
| * Account login information: username |
| */ |
| std::string username_; |
| |
| /** |
| * Account login information: hostname |
| */ |
| std::string hostname_; |
| |
| /** |
| * Account login information: Alias |
| */ |
| std::string alias_; |
| |
| /** |
| * Tells if the account is enabled. |
| * This implies the link will be initialized on startup. |
| * Modified by the configuration (key: ENABLED) |
| */ |
| bool enabled_; |
| |
| /** |
| * Tells if the account is active now. |
| * This allows doRegister to be called. |
| * When an account is unactivated, doUnregister must be called. |
| */ |
| bool active_ {true}; |
| |
| /* If true, automatically answer calls to this account */ |
| bool autoAnswerEnabled_; |
| |
| // If true, send Displayed status (and emit to the client) |
| bool sendReadReceipt_; |
| |
| /* If true mix calls into a conference */ |
| bool isRendezVous_; |
| |
| /** |
| * The number of concurrent calls for the account |
| * -1: Unlimited |
| * 0: Do not disturb |
| * 1: Single call |
| * +: Multi line |
| */ |
| int activeCallLimit_ {-1}; |
| |
| /* |
| * The general, protocol neutral registration |
| * state of the account |
| */ |
| RegistrationState registrationState_; |
| |
| /** |
| * Vector containing all system codecs (with default parameters) |
| */ |
| std::shared_ptr<SystemCodecContainer> systemCodecContainer_; |
| /** |
| * Vector containing all account codecs (set of system codecs with custom parameters) |
| */ |
| std::vector<std::shared_ptr<AccountCodecInfo>> accountCodecInfoList_; |
| |
| /** |
| * Ringtone .au file used for this account |
| */ |
| std::string ringtonePath_; |
| |
| /** |
| * Allows user to temporarily disable video calling |
| */ |
| |
| bool videoEnabled_ = true; |
| |
| /** |
| * Play ringtone when receiving a call |
| */ |
| bool ringtoneEnabled_; |
| |
| /** |
| * Display name when calling |
| */ |
| std::string displayName_; |
| |
| /** |
| * User-agent used for registration |
| */ |
| std::string customUserAgent_; |
| |
| // true if user has overridden default |
| bool hasCustomUserAgent_; |
| |
| /** |
| * Account mail box |
| */ |
| std::string mailBox_; |
| |
| /** |
| * UPnP IGD controller and the mutex to access it |
| */ |
| bool upnpEnabled_; |
| mutable std::mutex upnp_mtx {}; |
| std::shared_ptr<jami::upnp::Controller> upnpCtrl_; |
| |
| std::set<std::string> defaultModerators_ {}; |
| bool localModeratorsEnabled_; |
| bool allModeratorsEnabled_; |
| |
| bool multiStreamEnabled_ {false}; |
| bool iceForMediaEnabled_ {true}; |
| bool iceCompIdRfc5245Compliant_ {false}; |
| |
| /** |
| * Allow generating empty offers. Mainly to validate proper |
| * handling of incoming empty offers. |
| */ |
| bool emptyOffersEnabled_ {false}; |
| |
| /** |
| * Device push notification token. |
| */ |
| std::string deviceKey_ {}; |
| |
| /** |
| * private account codec searching functions |
| */ |
| std::shared_ptr<AccountCodecInfo> searchCodecByName(const std::string& name, |
| MediaType mediaType); |
| std::vector<unsigned> getAccountCodecInfoIdList(MediaType mediaType) const; |
| void setAllCodecsActive(MediaType mediaType, bool active); |
| void sortCodec(); |
| }; |
| |
| static inline std::ostream& |
| operator<<(std::ostream& os, const Account& acc) |
| { |
| os << "[Account " << acc.getAccountID() << "] "; |
| return os; |
| } |
| |
| } // namespace jami |
| |
| #endif |