Ring Daemon 16.0.0
Loading...
Searching...
No Matches
account.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2025 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "media/media_codec.h"
19#ifdef HAVE_CONFIG_H
20#include "config.h"
21#endif
22#include "account.h"
23
24#include <algorithm>
25#include <iterator>
26#include <mutex>
27
28#ifdef ENABLE_VIDEO
29#include "libav_utils.h"
30#endif
31
32#include "logger.h"
33#include "manager.h"
34
35#include <opendht/rng.h>
36
37#include "client/ring_signal.h"
38#include "account_schema.h"
39#include "jami/account_const.h"
40#include "string_utils.h"
41#include "fileutils.h"
42#include "config/yamlparser.h"
44#include "vcard.h"
45
46#pragma GCC diagnostic push
47#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
48#include <yaml-cpp/yaml.h>
49#pragma GCC diagnostic pop
50
51#include "compiler_intrinsics.h"
52#include "jami/account_const.h"
53
54#include <dhtnet/upnp/upnp_control.h>
55#include <dhtnet/ip_utils.h>
56
57#include <fmt/ranges.h>
58
59using namespace std::literals;
60
61namespace jami {
62
63// For portability, do not specify the absolute filename of the ringtone.
64// Instead, specify its base name to be looked in
65// JAMI_DATADIR/ringtones/, where JAMI_DATADIR is a preprocessor macro denoting
66// the data directory prefix that must be set at build time.
68
69Account::Account(const std::string& accountId)
70 : rand(Manager::instance().getSeededRandomEngine())
71 , accountID_(accountId)
72 , systemCodecContainer_(getSystemCodecContainer())
73 , idPath_(fileutils::get_data_dir() / accountId)
74{
75 // Initialize the codec order, used when creating a new account
77}
78
80
81void
83{
84 for (const auto& callId : callSet_.getCallIds())
86}
87
88void
90{
91 std::lock_guard lk {upnp_mtx};
92
93 if (not config().upnpEnabled or not isUsable()) {
94 upnpCtrl_.reset();
95 return;
96 }
97
98 // UPNP enabled. Create new controller if needed.
99 if (not upnpCtrl_) {
100 upnpCtrl_ = std::make_shared<dhtnet::upnp::Controller>(Manager::instance().upnpContext());
101 if (not upnpCtrl_) {
102 throw std::runtime_error("Failed to create a UPNP Controller instance!");
103 }
104 }
105}
106
107void
109 int detail_code,
110 const std::string& detail_str)
111{
112 if (state != registrationState_) {
113 registrationState_ = state;
114 // Notify the client
115 runOnMainThread([accountId = accountID_,
117 detail_code,
118 detail_str,
119 details = getVolatileAccountDetails()] {
121 state,
123 detail_str);
124
126 });
127 }
128}
129
130void
132{
133 // default codec are system codecs
134 const auto& systemCodecList = systemCodecContainer_->getSystemCodecInfoList();
135 accountCodecInfoList_.clear();
137 for (const auto& systemCodec : systemCodecList) {
138 // As defined in SDP RFC, only select a codec if it can encode and decode
140 continue;
141
142 if (systemCodec->mediaType & MEDIA_AUDIO) {
143 accountCodecInfoList_.emplace_back(std::make_shared<SystemAudioCodecInfo>(
144 *std::static_pointer_cast<SystemAudioCodecInfo>(systemCodec)));
145 }
146
147 if (systemCodec->mediaType & MEDIA_VIDEO) {
148 accountCodecInfoList_.emplace_back(std::make_shared<SystemVideoCodecInfo>(
149 *std::static_pointer_cast<SystemVideoCodecInfo>(systemCodec)));
150 }
151 }
152}
153
154void
156 setActiveCodecs(config_->activeCodecs);
157
158 // Try to get the client-defined resource base directory, if any. If not set, use the default
159 // JAMI_DATADIR that was set at build time.
162 // If the user defined a custom ringtone, the file may not exists
163 // In this case, fallback on the default ringtone path
164 if (not std::filesystem::is_regular_file(ringtonePath_)) {
165 JAMI_WARNING("Ringtone {} is not a valid file", ringtonePath_);
166 config_->ringtonePath = DEFAULT_RINGTONE_PATH;
168 }
170}
171
172void
177
178std::map<std::string, std::string>
184
185std::map<std::string, std::string>
187{
188 try {
189 auto path = idPath_ / "profile.vcf";
190 if (!std::filesystem::exists(path))
191 return {};
193 } catch (const std::exception& e) {
194 JAMI_ERROR("Error reading profile: {}", e.what());
195 return {};
196 }
197}
198
199bool
201{
202 for (auto& codecIt : accountCodecInfoList_)
203 if ((codecIt->mediaType & mediaType) && codecIt->isActive)
204 return true;
205 return false;
206}
207
208void
209Account::setActiveCodecs(const std::vector<unsigned>& list)
210{
211 // first clear the previously stored codecs
212 // TODO: mutex to protect isActive
214
215 // list contains the ordered payload of active codecs picked by the user for this account
216 // we used the codec vector to save the order.
217 uint16_t order = 1;
218 for (const auto& item : list) {
219 if (auto accCodec = searchCodecById(item, MEDIA_ALL)) {
220 accCodec->isActive = true;
221 accCodec->order = order;
222 ++order;
223 }
224 }
225 sortCodec();
226}
227
228void
230{
231 std::sort(std::begin(accountCodecInfoList_),
232 std::end(accountCodecInfoList_),
233 [](const std::shared_ptr<SystemCodecInfo>& a,
234 const std::shared_ptr<SystemCodecInfo>& b) { return a->order < b->order; });
235}
236
237std::string
239{
240#define CASE_STATE(X) \
241 case RegistrationState::X: \
242 return #X
243
244 switch (state) {
256 default:
258 }
259
260#undef CASE_STATE
261}
262
263std::vector<unsigned>
265{
266 return getSystemCodecContainer()->getSystemCodecInfoIdList(MEDIA_ALL);
267}
268
269std::map<std::string, std::string>
271{
272 auto codec = jami::getSystemCodecContainer()->searchCodecById(codecId, jami::MEDIA_ALL);
273 if (codec) {
274 if (codec->mediaType & jami::MEDIA_AUDIO) {
275 auto audioCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec);
276 return audioCodec->getCodecSpecifications();
277 }
278 if (codec->mediaType & jami::MEDIA_VIDEO) {
279 auto videoCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec);
280 return videoCodec->getCodecSpecifications();
281 }
282 }
283 return {};
284}
285
290dhtnet::IpAddr
292{
293 std::lock_guard lk(upnp_mtx);
294 if (upnpCtrl_)
295 return upnpCtrl_->getExternalIP();
296 return {};
297}
298
303bool
305{
306 std::lock_guard lk(upnp_mtx);
307 if (upnpCtrl_)
308 return upnpCtrl_->isReady();
309 return false;
310}
311
312/*
313 * private account codec searching functions
314 *
315 * */
316std::shared_ptr<SystemCodecInfo>
318{
319 if (mediaType != MEDIA_NONE) {
320 for (auto& codecIt : accountCodecInfoList_) {
321 if ((codecIt->id == codecId)
322 && (codecIt->mediaType & mediaType))
323 return codecIt;
324 }
325 }
326 return {};
327}
328
329std::shared_ptr<SystemCodecInfo>
330Account::searchCodecByName(const std::string& name, MediaType mediaType)
331{
332 if (mediaType != MEDIA_NONE) {
333 for (auto& codecIt : accountCodecInfoList_) {
334 if (codecIt->name == name
335 && (codecIt->mediaType & mediaType))
336 return codecIt;
337 }
338 }
339 return {};
340}
341
342std::shared_ptr<SystemCodecInfo>
343Account::searchCodecByPayload(unsigned payload, MediaType mediaType)
344{
345 if (mediaType != MEDIA_NONE) {
346 for (auto& codecIt : accountCodecInfoList_) {
347 if ((codecIt->payloadType == payload)
348 && (codecIt->mediaType & mediaType))
349 return codecIt;
350 }
351 }
352 return {};
353}
354
355std::vector<unsigned>
357{
358 if (mediaType == MEDIA_NONE)
359 return {};
360
361 std::vector<unsigned> idList;
362 for (auto& codecIt : accountCodecInfoList_) {
363 if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
364 idList.push_back(codecIt->id);
365 }
366 return idList;
367}
368
369std::vector<unsigned>
371{
372 if (mediaType == MEDIA_NONE)
373 return {};
374
375 std::vector<unsigned> idList;
376 for (auto& codecIt : accountCodecInfoList_) {
377 if (codecIt->mediaType & mediaType)
378 idList.push_back(codecIt->id);
379 }
380
381 return idList;
382}
383
384void
386{
387 if (mediaType == MEDIA_NONE)
388 return;
389 for (auto& codecIt : accountCodecInfoList_) {
390 if (codecIt->mediaType & mediaType)
391 codecIt->isActive = active;
392 }
393}
394
395void
397{
398 for (auto& codecIt : accountCodecInfoList_) {
399 if (codecIt->avcodecId == codecId)
400 codecIt->isActive = true;
401 }
402}
403
404void
406{
407 for (auto& codecIt : accountCodecInfoList_) {
408 if (codecIt->avcodecId == codecId)
409 codecIt->isActive = false;
410 }
411}
412
413std::vector<std::shared_ptr<SystemCodecInfo>>
415{
416 if (mediaType == MEDIA_NONE)
417 return {};
418
419 std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecList;
420 for (auto& codecIt : accountCodecInfoList_) {
421 if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
422 accountCodecList.push_back(codecIt);
423 }
424
425 return accountCodecList;
426}
427
428const std::string&
430{
431 return config_->customUserAgent.empty() ? DEFAULT_USER_AGENT : config_->customUserAgent;
432}
433
434std::string
436{
437 return fmt::format("{:s} {:s} ({:s})", PACKAGE_NAME, libjami::version(), jami::platform());
438}
439
440void
441Account::addDefaultModerator(const std::string& uri)
442{
443 config_->defaultModerators.insert(uri);
444}
445
446void
447Account::removeDefaultModerator(const std::string& uri)
448{
449 config_->defaultModerators.erase(uri);
450}
451
452bool
453Account::meetMinimumRequiredVersion(const std::vector<unsigned>& version,
454 const std::vector<unsigned>& minRequiredVersion)
455{
456 for (size_t i = 0; i < minRequiredVersion.size(); i++) {
457 if (i == version.size() or version[i] < minRequiredVersion[i])
458 return false;
460 return true;
461 }
462 return true;
463}
464
465bool
466Account::setPushNotificationConfig(const std::map<std::string, std::string>& data)
467{
468 std::lock_guard lock(configurationMutex_);
469 auto platform = data.find("platform");
470 auto topic = data.find("topic");
471 auto token = data.find("token");
472 bool changed = false;
473 if (platform != data.end() && config_->platform != platform->second) {
474 config_->platform = platform->second;
475 changed = true;
476 }
477 if (topic != data.end() && config_->notificationTopic != topic->second) {
478 config_->notificationTopic = topic->second;
479 changed = true;
480 }
481 if (token != data.end() && config_->deviceKey != token->second) {
482 config_->deviceKey = token->second;
483 changed = true;
484 }
485 if (changed)
486 saveConfig();
487 return changed;
488}
489
490} // namespace jami
#define CASE_STATE(X)
Interface to protocol account (ex: SIPAccount) It can be enable on loading or activate after.
Account specific keys/constants that must be shared in daemon and clients.
virtual ~Account()
Virtual destructor.
Definition account.cpp:79
virtual bool setPushNotificationConfig(const std::map< std::string, std::string > &data)
Definition account.cpp:466
bool hasActiveCodec(MediaType mediaType) const
Definition account.cpp:200
virtual void updateUpnpController()
Definition account.cpp:89
void loadDefaultCodecs()
Helper function used to load the default codec order from the codec factory.
Definition account.cpp:131
std::shared_ptr< SystemCodecInfo > searchCodecById(unsigned codecId, MediaType mediaType)
Definition account.cpp:317
static std::vector< unsigned > getDefaultCodecsId()
Definition account.cpp:264
std::vector< std::shared_ptr< SystemCodecInfo > > accountCodecInfoList_
Vector containing all account codecs (set of system codecs with custom parameters)
Definition account.h:495
const std::string & getAccountID() const
Get the account ID.
Definition account.h:154
void setCodecInactive(unsigned codecId)
Definition account.cpp:405
virtual void setRegistrationState(RegistrationState state, int detail_code=0, const std::string &detail_str={})
Set the registration state of the specified link.
Definition account.cpp:108
std::vector< unsigned > getActiveCodecs(MediaType mediaType=MEDIA_ALL) const
Definition account.cpp:356
static std::string getDefaultUserAgent()
Build the user-agent string.
Definition account.cpp:435
virtual void setActiveCodecs(const std::vector< unsigned > &list)
Update both the codec order structure and the codec string used for SDP offer and configuration respe...
Definition account.cpp:209
const std::string accountID_
Account ID are assign in constructor and shall not changed.
Definition account.h:471
static bool meetMinimumRequiredVersion(const std::vector< unsigned > &jamiVersion, const std::vector< unsigned > &minRequiredVersion)
Definition account.cpp:453
std::shared_ptr< SystemCodecInfo > searchCodecByName(const std::string &name, MediaType mediaType)
private account codec searching functions
Definition account.cpp:330
RegistrationState registrationState_
Definition account.h:486
std::filesystem::path idPath_
path to account
Definition account.h:500
bool isUsable() const
Definition account.h:280
std::shared_ptr< SystemCodecContainer > systemCodecContainer_
Vector containing all system codecs (with default parameters)
Definition account.h:491
void addDefaultModerator(const std::string &peerURI)
Definition account.cpp:441
static std::string mapStateNumberToString(RegistrationState state)
Definition account.cpp:238
virtual std::map< std::string, std::string > getVolatileAccountDetails() const
Definition account.cpp:179
std::vector< std::shared_ptr< SystemCodecInfo > > getActiveAccountCodecInfoList(MediaType mediaType) const
Definition account.cpp:414
std::vector< unsigned > getAccountCodecInfoIdList(MediaType mediaType) const
Definition account.cpp:370
std::mutex upnp_mtx
UPnP IGD controller and the mutex to access it.
Definition account.h:510
void removeDefaultModerator(const std::string &peerURI)
Definition account.cpp:447
static const std::string DEFAULT_USER_AGENT
Definition account.h:459
std::map< std::string, std::string > getProfileVcard() const
Definition account.cpp:186
std::unique_ptr< AccountConfig > config_
Definition account.h:455
dhtnet::IpAddr getUPnPIpAddress() const
Get the UPnP IP (external router) address.
Definition account.cpp:291
std::recursive_mutex configurationMutex_
Definition account.h:473
const std::string & getUserAgentName()
Get the user-agent.
Definition account.cpp:429
void setCodecActive(unsigned codecId)
Definition account.cpp:396
void hangupCalls()
Free all ressources related to this account.
Definition account.cpp:82
bool getUPnPActive() const
returns whether or not UPnP is enabled and active ie: if it is able to make port mappings
Definition account.cpp:304
const AccountConfig & config() const
Definition account.h:113
std::shared_ptr< SystemCodecInfo > searchCodecByPayload(unsigned payload, MediaType mediaType)
Definition account.cpp:343
bool active_
Tells if the account is active now.
Definition account.h:480
std::filesystem::path ringtonePath_
Ringtone .au file used for this account.
Definition account.h:505
static std::map< std::string, std::string > getDefaultCodecDetails(const unsigned &codecId)
Definition account.cpp:270
void setAllCodecsActive(MediaType mediaType, bool active)
Definition account.cpp:385
virtual void saveConfig() const
Definition account.cpp:173
virtual void loadConfig()
Load the settings in this account.
Definition account.cpp:155
std::shared_ptr< dhtnet::upnp::Controller > upnpCtrl_
Definition account.h:511
void sortCodec()
Definition account.cpp:229
Account(const std::string &accountID)
Definition account.cpp:69
std::vector< std::string > getCallIds() const
Definition call_set.h:66
Manager (controller) of daemon.
Definition manager.h:67
static LIBJAMI_TEST_EXPORT Manager & instance()
Definition manager.cpp:676
void saveConfig()
Save config to file.
Definition manager.cpp:1751
bool hangupCall(const std::string &accountId, const std::string &callId)
Functions which occur with a user's action Hangup the call.
Definition manager.cpp:1142
#define JAMI_ERROR(formatstr,...)
Definition logger.h:228
#define JAMI_WARNING(formatstr,...)
Definition logger.h:227
static const char *const CONFIG_ACCOUNT_REGISTRATION_STATUS
std::filesystem::path getFullPath(const std::filesystem::path &base, const std::filesystem::path &path)
If path is relative, it is appended to base.
const std::filesystem::path & get_resource_dir_path()
Get the resource directory path that was set with set_resource_dir_path.
std::string loadTextFile(const std::filesystem::path &path, const std::filesystem::path &default_dir)
static constexpr int version
RegistrationState
Contains all the Registration states for an account can be in.
decltype(getGlobalInstance< SystemCodecContainer >) & getSystemCodecContainer
static constexpr const char TRUE_STR[]
constexpr std::string_view platform()
void emitSignal(Args... args)
Definition ring_signal.h:64
@ CODEC_ENCODER_DECODER
Definition media_codec.h:42
static constexpr const char FALSE_STR[]
static constexpr const char RINGDIR[]
Definition account.h:63
@ MEDIA_AUDIO
Definition media_codec.h:47
@ MEDIA_ALL
Definition media_codec.h:49
@ MEDIA_VIDEO
Definition media_codec.h:48
@ MEDIA_NONE
Definition media_codec.h:46
static void runOnMainThread(Callback &&cb)
Definition manager.h:909
constexpr const char *const DEFAULT_RINGTONE_PATH
static constexpr const char ERROR_GENERIC[]
static constexpr const char ACTIVE[]
const char * version() noexcept
Return the library version as string.
Definition buildinfo.cpp:43
std::map< std::string, std::string > toMap(std::string_view content)
Payload to vCard.
Definition vcard.cpp:25