Ring Daemon
Loading...
Searching...
No Matches
account.cpp
Go to the documentation of this file.
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
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#include <fstream>
28
29#include "logger.h"
30#include "manager.h"
31
32#include <opendht/rng.h>
33
34#include "client/jami_signal.h"
35#include "account_schema.h"
36#include "jami/account_const.h"
37#include "string_utils.h"
38#include "fileutils.h"
40#include "vcard.h"
41
42#pragma GCC diagnostic push
43#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
44#include <yaml-cpp/yaml.h>
45#pragma GCC diagnostic pop
46
47#include "jami/account_const.h"
48
49#include <dhtnet/upnp/upnp_control.h>
50#include <dhtnet/ip_utils.h>
51
52#include <fmt/ranges.h>
53
54using namespace std::literals;
55
56namespace jami {
57
58// For portability, do not specify the absolute filename of the ringtone.
59// Instead, specify its base name to be looked in
60// JAMI_DATADIR/ringtones/, where JAMI_DATADIR is a preprocessor macro denoting
61// the data directory prefix that must be set at build time.
63
64Account::Account(const std::string& accountId)
65 : rand(Manager::instance().getSeededRandomEngine())
66 , accountID_(accountId)
67 , systemCodecContainer_(getSystemCodecContainer())
68 , idPath_(fileutils::get_data_dir() / accountId)
69{
70 // Initialize the codec order, used when creating a new account
72}
73
75
76void
78{
79 for (const auto& callId : callSet_.getCallIds())
81}
82
83void
85{
86 std::lock_guard lk {upnp_mtx};
87
88 if (not config().upnpEnabled or not isUsable()) {
89 upnpCtrl_.reset();
90 return;
91 }
92
93 // UPNP enabled. Create new controller if needed.
94 if (not upnpCtrl_) {
95 upnpCtrl_ = std::make_shared<dhtnet::upnp::Controller>(Manager::instance().upnpContext());
96 if (not upnpCtrl_) {
97 throw std::runtime_error("Failed to create a UPNP Controller instance!");
98 }
99 }
100}
101
102void
103Account::setRegistrationState(RegistrationState state, int detail_code, const std::string& detail_str)
104{
105 if (state != registrationState_) {
106 registrationState_ = state;
107 // Notify the client
108 runOnMainThread([accountId = accountID_,
110 detail_code,
111 detail_str,
112 details = getVolatileAccountDetails()] {
114 state,
116 detail_str);
117
119 });
120 }
121}
122
123void
125{
126 // default codec are system codecs
127 const auto& systemCodecList = systemCodecContainer_->getSystemCodecInfoList();
128 accountCodecInfoList_.clear();
130 for (const auto& systemCodec : systemCodecList) {
131 // As defined in SDP RFC, only select a codec if it can encode and decode
133 continue;
134
135 if (systemCodec->mediaType & MEDIA_AUDIO) {
136 accountCodecInfoList_.emplace_back(
137 std::make_shared<SystemAudioCodecInfo>(*std::static_pointer_cast<SystemAudioCodecInfo>(systemCodec)));
138 }
139
140 if (systemCodec->mediaType & MEDIA_VIDEO) {
141 accountCodecInfoList_.emplace_back(
142 std::make_shared<SystemVideoCodecInfo>(*std::static_pointer_cast<SystemVideoCodecInfo>(systemCodec)));
143 }
144 }
145}
146
147void
149{
150 setActiveCodecs(config_->activeCodecs);
151
152 // Try to get the client-defined resource base directory, if any. If not set, use the default
153 // JAMI_DATADIR that was set at build time.
156 // If the user defined a custom ringtone, the file may not exists or may not allow access
157 // In this case, fallback on the default ringtone path
158 std::ifstream f(ringtonePath_);
159 if (not std::filesystem::is_regular_file(ringtonePath_) || !f.is_open()) {
160 JAMI_WARNING("Ringtone {} is not a valid file", ringtonePath_);
161 config_->ringtonePath = DEFAULT_RINGTONE_PATH;
163 }
165}
166
167void
172
173std::map<std::string, std::string>
179
182{
183 try {
184 auto path = idPath_ / "profile.vcf";
185 if (!std::filesystem::exists(path))
186 return {};
188 } catch (const std::exception& e) {
189 JAMI_ERROR("Error reading profile: {}", e.what());
190 return {};
191 }
192}
193
194bool
196{
197 for (auto& codecIt : accountCodecInfoList_)
198 if ((codecIt->mediaType & mediaType) && codecIt->isActive)
199 return true;
200 return false;
201}
202
203void
204Account::setActiveCodecs(const std::vector<unsigned>& list)
205{
206 // first clear the previously stored codecs
207 // TODO: mutex to protect isActive
209
210 // list contains the ordered payload of active codecs picked by the user for this account
211 // we used the codec vector to save the order.
212 uint16_t order = 1;
213 for (const auto& item : list) {
214 if (auto accCodec = searchCodecById(item, MEDIA_ALL)) {
215 accCodec->isActive = true;
216 accCodec->order = order;
217 ++order;
218 }
219 }
220 sortCodec();
221}
222
223void
225{
226 std::sort(std::begin(accountCodecInfoList_),
227 std::end(accountCodecInfoList_),
228 [](const std::shared_ptr<SystemCodecInfo>& a, const std::shared_ptr<SystemCodecInfo>& b) {
229 return a->order < b->order;
230 });
231}
232
233std::string
235{
236#define CASE_STATE(X) \
237 case RegistrationState::X: \
238 return #X
239
240 switch (state) {
252 default:
254 }
255
256#undef CASE_STATE
257}
258
259std::vector<unsigned>
261{
262 return getSystemCodecContainer()->getSystemCodecInfoIdList(MEDIA_ALL);
263}
264
265std::map<std::string, std::string>
267{
268 auto codec = jami::getSystemCodecContainer()->searchCodecById(codecId, jami::MEDIA_ALL);
269 if (codec) {
270 if (codec->mediaType & jami::MEDIA_AUDIO) {
271 auto audioCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec);
272 return audioCodec->getCodecSpecifications();
273 }
274 if (codec->mediaType & jami::MEDIA_VIDEO) {
275 auto videoCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec);
276 return videoCodec->getCodecSpecifications();
277 }
278 }
279 return {};
280}
281
286dhtnet::IpAddr
288{
289 std::lock_guard lk(upnp_mtx);
290 if (upnpCtrl_)
291 return upnpCtrl_->getExternalIP();
292 return {};
293}
294
299bool
301{
302 std::lock_guard lk(upnp_mtx);
303 if (upnpCtrl_)
304 return upnpCtrl_->isReady();
305 return false;
306}
307
308/*
309 * private account codec searching functions
310 *
311 * */
312std::shared_ptr<SystemCodecInfo>
314{
315 if (mediaType != MEDIA_NONE) {
316 for (auto& codecIt : accountCodecInfoList_) {
317 if ((codecIt->id == codecId) && (codecIt->mediaType & mediaType))
318 return codecIt;
319 }
320 }
321 return {};
322}
323
324std::shared_ptr<SystemCodecInfo>
325Account::searchCodecByName(const std::string& name, MediaType mediaType)
326{
327 if (mediaType != MEDIA_NONE) {
328 for (auto& codecIt : accountCodecInfoList_) {
329 if (codecIt->name == name && (codecIt->mediaType & mediaType))
330 return codecIt;
331 }
332 }
333 return {};
334}
335
336std::shared_ptr<SystemCodecInfo>
337Account::searchCodecByPayload(unsigned payload, MediaType mediaType)
338{
339 if (mediaType != MEDIA_NONE) {
340 for (auto& codecIt : accountCodecInfoList_) {
341 if ((codecIt->payloadType == payload) && (codecIt->mediaType & mediaType))
342 return codecIt;
343 }
344 }
345 return {};
346}
347
348std::vector<unsigned>
350{
351 if (mediaType == MEDIA_NONE)
352 return {};
353
354 std::vector<unsigned> idList;
355 for (auto& codecIt : accountCodecInfoList_) {
356 if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
357 idList.push_back(codecIt->id);
358 }
359 return idList;
360}
361
362std::vector<unsigned>
364{
365 if (mediaType == MEDIA_NONE)
366 return {};
367
368 std::vector<unsigned> idList;
369 for (auto& codecIt : accountCodecInfoList_) {
370 if (codecIt->mediaType & mediaType)
371 idList.push_back(codecIt->id);
372 }
373
374 return idList;
375}
376
377void
379{
380 if (mediaType == MEDIA_NONE)
381 return;
382 for (auto& codecIt : accountCodecInfoList_) {
383 if (codecIt->mediaType & mediaType)
384 codecIt->isActive = active;
385 }
386}
387
388void
390{
391 for (auto& codecIt : accountCodecInfoList_) {
392 if (codecIt->avcodecId == codecId)
393 codecIt->isActive = true;
394 }
395}
396
397void
399{
400 for (auto& codecIt : accountCodecInfoList_) {
401 if (codecIt->avcodecId == codecId)
402 codecIt->isActive = false;
403 }
404}
405
406std::vector<std::shared_ptr<SystemCodecInfo>>
408{
409 if (mediaType == MEDIA_NONE)
410 return {};
411
412 std::vector<std::shared_ptr<SystemCodecInfo>> accountCodecList;
413 for (auto& codecIt : accountCodecInfoList_) {
414 if ((codecIt->mediaType & mediaType) && (codecIt->isActive))
415 accountCodecList.push_back(codecIt);
416 }
417
418 return accountCodecList;
419}
420
421const std::string&
423{
424 return config_->customUserAgent.empty() ? DEFAULT_USER_AGENT : config_->customUserAgent;
425}
426
427std::string
429{
430 return fmt::format("{:s} {:s} ({:s})", PACKAGE_NAME, libjami::version(), jami::platform());
431}
432
433void
434Account::addDefaultModerator(const std::string& uri)
435{
436 config_->defaultModerators.insert(uri);
437}
438
439void
440Account::removeDefaultModerator(const std::string& uri)
441{
442 config_->defaultModerators.erase(uri);
443}
444
445bool
446Account::meetMinimumRequiredVersion(const std::vector<unsigned>& version,
447 const std::vector<unsigned>& minRequiredVersion)
448{
449 for (size_t i = 0; i < minRequiredVersion.size(); i++) {
450 if (i == version.size() or version[i] < minRequiredVersion[i])
451 return false;
453 return true;
454 }
455 return true;
456}
457
458bool
459Account::setPushNotificationConfig(const std::map<std::string, std::string>& data)
460{
461 std::lock_guard lock(configurationMutex_);
462 auto platform = data.find("platform");
463 auto topic = data.find("topic");
464 auto token = data.find("token");
465 bool changed = false;
466 if (platform != data.end() && config_->platform != platform->second) {
467 config_->platform = platform->second;
468 changed = true;
469 }
470 if (topic != data.end() && config_->notificationTopic != topic->second) {
471 config_->notificationTopic = topic->second;
472 changed = true;
473 }
474 if (token != data.end() && config_->deviceKey != token->second) {
475 config_->deviceKey = token->second;
476 changed = true;
477 }
478 if (changed)
479 saveConfig();
480 return changed;
481}
482
483} // 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:74
virtual bool setPushNotificationConfig(const std::map< std::string, std::string > &data)
Definition account.cpp:459
bool hasActiveCodec(MediaType mediaType) const
Definition account.cpp:195
virtual void updateUpnpController()
Definition account.cpp:84
void loadDefaultCodecs()
Helper function used to load the default codec order from the codec factory.
Definition account.cpp:124
std::shared_ptr< SystemCodecInfo > searchCodecById(unsigned codecId, MediaType mediaType)
Definition account.cpp:313
static std::vector< unsigned > getDefaultCodecsId()
Definition account.cpp:260
std::vector< std::shared_ptr< SystemCodecInfo > > accountCodecInfoList_
Vector containing all account codecs (set of system codecs with custom parameters)
Definition account.h:477
const std::string & getAccountID() const
Get the account ID.
Definition account.h:149
void setCodecInactive(unsigned codecId)
Definition account.cpp:398
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:103
std::vector< unsigned > getActiveCodecs(MediaType mediaType=MEDIA_ALL) const
Definition account.cpp:349
static std::string getDefaultUserAgent()
Build the user-agent string.
Definition account.cpp:428
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:204
const std::string accountID_
Account ID are assign in constructor and shall not changed.
Definition account.h:453
static bool meetMinimumRequiredVersion(const std::vector< unsigned > &jamiVersion, const std::vector< unsigned > &minRequiredVersion)
Definition account.cpp:446
std::shared_ptr< SystemCodecInfo > searchCodecByName(const std::string &name, MediaType mediaType)
private account codec searching functions
Definition account.cpp:325
RegistrationState registrationState_
Definition account.h:468
std::filesystem::path idPath_
path to account
Definition account.h:482
bool isUsable() const
Definition account.h:271
std::shared_ptr< SystemCodecContainer > systemCodecContainer_
Vector containing all system codecs (with default parameters)
Definition account.h:473
void addDefaultModerator(const std::string &peerURI)
Definition account.cpp:434
static std::string mapStateNumberToString(RegistrationState state)
Definition account.cpp:234
virtual std::map< std::string, std::string > getVolatileAccountDetails() const
Definition account.cpp:174
std::vector< std::shared_ptr< SystemCodecInfo > > getActiveAccountCodecInfoList(MediaType mediaType) const
Definition account.cpp:407
std::vector< unsigned > getAccountCodecInfoIdList(MediaType mediaType) const
Definition account.cpp:363
std::mutex upnp_mtx
UPnP IGD controller and the mutex to access it.
Definition account.h:492
void removeDefaultModerator(const std::string &peerURI)
Definition account.cpp:440
static const std::string DEFAULT_USER_AGENT
Definition account.h:441
std::unique_ptr< AccountConfig > config_
Definition account.h:437
dhtnet::IpAddr getUPnPIpAddress() const
Get the UPnP IP (external router) address.
Definition account.cpp:287
std::recursive_mutex configurationMutex_
Definition account.h:455
const std::string & getUserAgentName()
Get the user-agent.
Definition account.cpp:422
void setCodecActive(unsigned codecId)
Definition account.cpp:389
void hangupCalls()
Free all ressources related to this account.
Definition account.cpp:77
bool getUPnPActive() const
returns whether or not UPnP is enabled and active ie: if it is able to make port mappings
Definition account.cpp:300
const AccountConfig & config() const
Definition account.h:108
std::shared_ptr< SystemCodecInfo > searchCodecByPayload(unsigned payload, MediaType mediaType)
Definition account.cpp:337
vCard::utils::VCardData getProfileVcard() const
Definition account.cpp:181
bool active_
Tells if the account is active now.
Definition account.h:462
std::filesystem::path ringtonePath_
Ringtone .au file used for this account.
Definition account.h:487
static std::map< std::string, std::string > getDefaultCodecDetails(const unsigned &codecId)
Definition account.cpp:266
void setAllCodecsActive(MediaType mediaType, bool active)
Definition account.cpp:378
virtual void saveConfig() const
Definition account.cpp:168
virtual void loadConfig()
Load the settings in this account.
Definition account.cpp:148
std::shared_ptr< dhtnet::upnp::Controller > upnpCtrl_
Definition account.h:493
void sortCodec()
Definition account.cpp:224
Account(const std::string &accountID)
Definition account.cpp:64
std::vector< std::string > getCallIds() const
Definition call_set.h:66
Manager (controller) of daemon.
Definition manager.h:66
static LIBJAMI_TEST_EXPORT Manager & instance()
Definition manager.cpp:694
void saveConfig()
Save config to file.
Definition manager.cpp:1755
bool hangupCall(const std::string &accountId, const std::string &callId)
Functions which occur with a user's action Hangup the call.
Definition manager.cpp:1158
#define JAMI_ERROR(formatstr,...)
Definition logger.h:243
#define JAMI_WARNING(formatstr,...)
Definition logger.h:242
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
std::map< std::string, std::string, std::less<> > VCardData
Definition vcard.h:89
VCardData toMap(std::string_view content)
Payload to vCard.
Definition vcard.cpp:31
decltype(getGlobalInstance< SystemCodecContainer >) & getSystemCodecContainer
static constexpr const char TRUE_STR[]
constexpr std::string_view platform()
void emitSignal(Args... args)
Definition jami_signal.h:64
static constexpr const char FALSE_STR[]
RegistrationState
Contains all the Registration states for an account can be in.
static constexpr const char RINGDIR[]
Definition account.h:58
@ CODEC_ENCODER_DECODER
Definition media_codec.h:41
@ MEDIA_AUDIO
Definition media_codec.h:46
@ MEDIA_ALL
Definition media_codec.h:48
@ MEDIA_VIDEO
Definition media_codec.h:47
@ MEDIA_NONE
Definition media_codec.h:45
static void runOnMainThread(Callback &&cb)
Definition manager.h:930
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:40