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 :
18 : #ifdef HAVE_CONFIG_H
19 : #include "config.h"
20 : #endif
21 :
22 : #include "configurationmanager_interface.h"
23 : #include "manager.h"
24 : #include "logger.h"
25 : #include "fileutils.h"
26 : #include "sip/sipaccount.h"
27 : #include "jamidht/jamiaccount.h"
28 : #include "sip/sipaccount_config.h"
29 : #include "jamidht/jamiaccount_config.h"
30 : #include "audio/audiolayer.h"
31 : #include "system_codec_container.h"
32 : #include "account_const.h"
33 : #include "client/jami_signal.h"
34 : #include "audio/ringbufferpool.h"
35 : #include "connectivity/security/tlsvalidator.h"
36 :
37 : #include <dhtnet/ip_utils.h>
38 : #include <dhtnet/upnp/upnp_context.h>
39 : #include <dhtnet/certstore.h>
40 :
41 : #ifdef __APPLE__
42 : #include <TargetConditionals.h>
43 : #endif
44 :
45 : #ifdef _MSC_VER
46 : #include "windirent.h"
47 : #else
48 : #include <dirent.h>
49 : #endif
50 :
51 : #include <cerrno>
52 : #include <cstring>
53 :
54 : #ifdef _WIN32
55 : #undef interface
56 : #endif
57 :
58 : namespace libjami {
59 :
60 : constexpr unsigned CODECS_NOT_LOADED = 0x1000; /** Codecs not found */
61 :
62 : using jami::SIPAccount;
63 : using jami::JamiAccount;
64 : using jami::tls::TlsValidator;
65 : using jami::AudioDeviceType;
66 :
67 : void
68 0 : registerConfHandlers(const std::map<std::string, std::shared_ptr<CallbackWrapperBase>>& handlers)
69 : {
70 0 : registerSignalHandlers(handlers);
71 0 : }
72 :
73 : std::map<std::string, std::string>
74 0 : getAccountDetails(const std::string& accountId)
75 : {
76 0 : return jami::Manager::instance().getAccountDetails(accountId);
77 : }
78 :
79 : std::map<std::string, std::string>
80 0 : getVolatileAccountDetails(const std::string& accountId)
81 : {
82 0 : return jami::Manager::instance().getVolatileAccountDetails(accountId);
83 : }
84 :
85 : std::map<std::string, std::string>
86 0 : validateCertificate(const std::string& accountId, const std::string& certificate)
87 : {
88 : try {
89 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
90 0 : return TlsValidator {acc->certStore(), acc->certStore().getCertificate(certificate)}.getSerializedChecks();
91 0 : } catch (const std::runtime_error& e) {
92 0 : JAMI_WARN("Certificate loading failed: %s", e.what());
93 0 : }
94 0 : return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
95 : }
96 :
97 : std::map<std::string, std::string>
98 0 : validateCertificatePath(const std::string& accountId,
99 : const std::string& certificate,
100 : const std::string& privateKey,
101 : const std::string& privateKeyPass,
102 : const std::string& caList)
103 : {
104 : try {
105 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
106 0 : return TlsValidator {acc->certStore(), certificate, privateKey, privateKeyPass, caList}.getSerializedChecks();
107 0 : } catch (const std::runtime_error& e) {
108 0 : JAMI_WARN("Certificate loading failed: %s", e.what());
109 0 : return {{Certificate::ChecksNames::EXIST, Certificate::CheckValuesNames::FAILED}};
110 0 : }
111 0 : return {};
112 : }
113 :
114 : std::map<std::string, std::string>
115 0 : getCertificateDetails(const std::string& accountId, const std::string& certificate)
116 : {
117 : try {
118 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
119 0 : return TlsValidator {acc->certStore(), acc->certStore().getCertificate(certificate)}.getSerializedDetails();
120 0 : } catch (const std::runtime_error& e) {
121 0 : JAMI_WARN("Certificate loading failed: %s", e.what());
122 0 : }
123 0 : return {};
124 : }
125 :
126 : std::map<std::string, std::string>
127 0 : getCertificateDetailsPath(const std::string& accountId,
128 : const std::string& certificate,
129 : const std::string& privateKey,
130 : const std::string& privateKeyPassword)
131 : {
132 : try {
133 0 : auto crt = std::make_shared<dht::crypto::Certificate>(jami::fileutils::loadFile(certificate));
134 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
135 0 : TlsValidator validator {acc->certStore(), certificate, privateKey, privateKeyPassword};
136 0 : acc->certStore().pinCertificate(validator.getCertificate(), false);
137 0 : return validator.getSerializedDetails();
138 0 : }
139 0 : } catch (const std::runtime_error& e) {
140 0 : JAMI_WARN("Certificate loading failed: %s", e.what());
141 0 : }
142 0 : return {};
143 : }
144 :
145 : std::vector<std::string>
146 0 : getPinnedCertificates(const std::string& accountId)
147 : {
148 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
149 0 : return acc->certStore().getPinnedCertificates();
150 0 : return {};
151 : }
152 :
153 : std::vector<std::string>
154 0 : pinCertificate(const std::string& accountId, const std::vector<uint8_t>& certificate, bool local)
155 : {
156 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
157 0 : return acc->certStore().pinCertificate(certificate, local);
158 0 : return {};
159 : }
160 :
161 : void
162 0 : pinCertificatePath(const std::string& accountId, const std::string& path)
163 : {
164 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
165 0 : acc->certStore().pinCertificatePath(path);
166 0 : }
167 :
168 : bool
169 0 : unpinCertificate(const std::string& accountId, const std::string& certId)
170 : {
171 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
172 0 : return acc->certStore().unpinCertificate(certId);
173 0 : return {};
174 : }
175 :
176 : unsigned
177 0 : unpinCertificatePath(const std::string& accountId, const std::string& path)
178 : {
179 0 : if (const auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
180 0 : return acc->certStore().unpinCertificatePath(path);
181 0 : return {};
182 : }
183 :
184 : bool
185 0 : pinRemoteCertificate(const std::string& accountId, const std::string& certId)
186 : {
187 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
188 0 : acc->dht()->findCertificate(dht::InfoHash(certId),
189 0 : [](const std::shared_ptr<dht::crypto::Certificate>& /*crt*/) {});
190 0 : return true;
191 0 : }
192 0 : return false;
193 : }
194 :
195 : bool
196 0 : setCertificateStatus(const std::string& accountId, const std::string& certId, const std::string& ststr)
197 : {
198 : try {
199 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
200 0 : auto status = dhtnet::tls::TrustStore::statusFromStr(ststr.c_str());
201 0 : return acc->setCertificateStatus(certId, status);
202 0 : }
203 0 : } catch (const std::out_of_range& e) {
204 0 : JAMI_WARNING("Argument out of range when setting certificate status: {}", e);
205 0 : }
206 0 : return false;
207 : }
208 :
209 : std::vector<std::string>
210 0 : getCertificatesByStatus(const std::string& accountId, const std::string& ststr)
211 : {
212 0 : auto status = dhtnet::tls::TrustStore::statusFromStr(ststr.c_str());
213 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
214 0 : return acc->getCertificatesByStatus(status);
215 0 : return {};
216 : }
217 :
218 : void
219 16 : setAccountDetails(const std::string& accountId, const std::map<std::string, std::string>& details)
220 : {
221 16 : jami::Manager::instance().setAccountDetails(accountId, details);
222 16 : }
223 :
224 : void
225 0 : setAccountActive(const std::string& accountId, bool enable, bool shutdownConnections)
226 : {
227 0 : jami::Manager::instance().setAccountActive(accountId, enable, shutdownConnections);
228 0 : }
229 :
230 : void
231 0 : loadAccountAndConversation(const std::string& accountId, bool loadAll, const std::string& convId)
232 : {
233 0 : jami::Manager::instance().loadAccountAndConversation(accountId, loadAll, convId);
234 0 : }
235 :
236 : void
237 0 : sendRegister(const std::string& accountId, bool enable)
238 : {
239 0 : jami::Manager::instance().sendRegister(accountId, enable);
240 0 : }
241 :
242 : bool
243 0 : isPasswordValid(const std::string& accountId, const std::string& password)
244 : {
245 0 : if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(accountId))
246 0 : return acc->isPasswordValid(password);
247 0 : return false;
248 : }
249 :
250 : std::vector<uint8_t>
251 0 : getPasswordKey(const std::string& accountID, const std::string& password)
252 : {
253 0 : if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(accountID))
254 0 : return acc->getPasswordKey(password);
255 0 : return {};
256 : }
257 :
258 : void
259 0 : registerAllAccounts()
260 : {
261 0 : jami::Manager::instance().registerAccounts();
262 0 : }
263 :
264 : uint64_t
265 0 : sendAccountTextMessage(const std::string& accountId,
266 : const std::string& to,
267 : const std::map<std::string, std::string>& payloads,
268 : int32_t flags)
269 : {
270 0 : bool onlyConnected = flags & 0x1;
271 0 : return jami::Manager::instance().sendTextMessage(accountId, to, payloads, onlyConnected);
272 : }
273 :
274 : std::vector<Message>
275 0 : getLastMessages(const std::string& accountId, const uint64_t& base_timestamp)
276 : {
277 0 : if (const auto acc = jami::Manager::instance().getAccount(accountId))
278 0 : return acc->getLastMessages(base_timestamp);
279 0 : return {};
280 : }
281 :
282 : std::map<std::string, std::string>
283 0 : getNearbyPeers(const std::string& accountId)
284 : {
285 0 : return jami::Manager::instance().getNearbyPeers(accountId);
286 : }
287 :
288 : void
289 0 : updateProfile(const std::string& accountId,
290 : const std::string& displayName,
291 : const std::string& avatar,
292 : const std::string& fileType,
293 : int32_t flag)
294 : {
295 0 : if (const auto acc = jami::Manager::instance().getAccount(accountId)) {
296 0 : acc->updateProfile(displayName, avatar, fileType, flag);
297 0 : }
298 0 : }
299 :
300 : int
301 0 : getMessageStatus(uint64_t messageId)
302 : {
303 0 : return jami::Manager::instance().getMessageStatus(messageId);
304 : }
305 :
306 : int
307 0 : getMessageStatus(const std::string& accountId, uint64_t messageId)
308 : {
309 0 : return jami::Manager::instance().getMessageStatus(accountId, messageId);
310 : }
311 :
312 : void
313 5 : setIsComposing(const std::string& accountId, const std::string& conversationUri, bool isWriting)
314 : {
315 5 : if (const auto acc = jami::Manager::instance().getAccount(accountId))
316 5 : acc->setIsComposing(conversationUri, isWriting);
317 5 : }
318 :
319 : bool
320 2 : setMessageDisplayed(const std::string& accountId,
321 : const std::string& conversationUri,
322 : const std::string& messageId,
323 : int status)
324 : {
325 2 : if (const auto acc = jami::Manager::instance().getAccount(accountId))
326 2 : return acc->setMessageDisplayed(conversationUri, messageId, status);
327 0 : return false;
328 : }
329 :
330 : int32_t
331 5 : addDevice(const std::string& accountId, const std::string& uri)
332 : {
333 20 : JAMI_DEBUG("[LinkDevice {}] exportToPeer called.", accountId);
334 5 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
335 5 : return account->addDevice(uri);
336 5 : }
337 0 : return static_cast<int32_t>(jami::AccountManager::AddDeviceError::GENERIC);
338 : }
339 :
340 : bool
341 0 : confirmAddDevice(const std::string& accountId, uint32_t op_id)
342 : {
343 0 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
344 0 : return account->confirmAddDevice(op_id);
345 0 : }
346 0 : return false;
347 : }
348 :
349 : bool
350 0 : cancelAddDevice(const std::string& accountId, uint32_t op_id)
351 : {
352 0 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
353 0 : return account->cancelAddDevice(op_id);
354 0 : }
355 0 : return false;
356 : }
357 :
358 : bool
359 0 : provideAccountAuthentication(const std::string& accountId,
360 : const std::string& credentialsFromUser,
361 : const std::string& scheme)
362 : {
363 0 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
364 : // send the password to the channel for communicationg with the old device
365 0 : account->provideAccountAuthentication(credentialsFromUser, scheme);
366 0 : return true;
367 0 : }
368 0 : return false;
369 : }
370 :
371 : bool
372 0 : exportToFile(const std::string& accountId,
373 : const std::string& destinationPath,
374 : const std::string& scheme,
375 : const std::string& password)
376 : {
377 0 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
378 0 : return account->exportArchive(destinationPath, scheme, password);
379 0 : }
380 0 : return false;
381 : }
382 :
383 : bool
384 0 : revokeDevice(const std::string& accountId,
385 : const std::string& deviceId,
386 : const std::string& scheme,
387 : const std::string& password)
388 : {
389 0 : if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
390 0 : return account->revokeDevice(deviceId, scheme, password);
391 0 : }
392 0 : return false;
393 : }
394 :
395 : std::map<std::string, std::string>
396 0 : getKnownRingDevices(const std::string& accountId)
397 : {
398 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
399 0 : return acc->getKnownDevices();
400 0 : return {};
401 : }
402 :
403 : bool
404 4 : changeAccountPassword(const std::string& accountId, const std::string& password_old, const std::string& password_new)
405 : {
406 4 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
407 4 : return acc->changeArchivePassword(password_old, password_new);
408 0 : return false;
409 : }
410 :
411 : /* contacts */
412 :
413 : void
414 0 : addContact(const std::string& accountId, const std::string& uri)
415 : {
416 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
417 0 : return acc->addContact(uri);
418 : }
419 :
420 : void
421 0 : removeContact(const std::string& accountId, const std::string& uri, bool ban)
422 : {
423 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
424 0 : return acc->removeContact(uri, ban);
425 : }
426 :
427 : std::map<std::string, std::string>
428 0 : getContactDetails(const std::string& accountId, const std::string& uri)
429 : {
430 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
431 0 : return acc->getContactDetails(uri);
432 0 : return {};
433 : }
434 :
435 : std::vector<std::map<std::string, std::string>>
436 1 : getContacts(const std::string& accountId)
437 : {
438 1 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
439 1 : return acc->getContacts();
440 0 : return {};
441 : }
442 :
443 : /* contact requests */
444 : std::vector<std::map<std::string, std::string>>
445 6 : getTrustRequests(const std::string& accountId)
446 : {
447 6 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
448 6 : return acc->getTrustRequests();
449 0 : return {};
450 : }
451 :
452 : bool
453 0 : acceptTrustRequest(const std::string& accountId, const std::string& from)
454 : {
455 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
456 0 : return acc->acceptTrustRequest(from);
457 0 : return false;
458 : }
459 :
460 : bool
461 0 : discardTrustRequest(const std::string& accountId, const std::string& from)
462 : {
463 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
464 0 : return acc->discardTrustRequest(from);
465 0 : return false;
466 : }
467 :
468 : void
469 0 : sendTrustRequest(const std::string& accountId, const std::string& to, const std::vector<uint8_t>& payload)
470 : {
471 0 : if (auto acc = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId))
472 0 : acc->sendTrustRequest(to, payload);
473 0 : }
474 :
475 : /// This function is used as a base for new accounts for clients that support it
476 : std::map<std::string, std::string>
477 307 : getAccountTemplate(const std::string& accountType)
478 : {
479 307 : if (accountType == Account::ProtocolNames::RING)
480 598 : return jami::JamiAccountConfig().toMap();
481 8 : else if (accountType == Account::ProtocolNames::SIP)
482 16 : return jami::SipAccountConfig().toMap();
483 0 : return {};
484 : }
485 :
486 : std::string
487 0 : addAccount(const std::map<std::string, std::string>& details, const std::string& accountId)
488 : {
489 0 : return jami::Manager::instance().addAccount(details, accountId);
490 : }
491 :
492 : void
493 0 : monitor(bool continuous)
494 : {
495 0 : return jami::Manager::instance().monitor(continuous);
496 : }
497 :
498 : std::vector<std::map<std::string, std::string>>
499 0 : getConnectionList(const std::string& accountId, const std::string& conversationId)
500 : {
501 0 : return jami::Manager::instance().getConnectionList(accountId, conversationId);
502 : }
503 :
504 : std::vector<std::map<std::string, std::string>>
505 0 : getChannelList(const std::string& accountId, const std::string& connectionId)
506 : {
507 0 : return jami::Manager::instance().getChannelList(accountId, connectionId);
508 : }
509 :
510 : void
511 0 : removeAccount(const std::string& accountId)
512 : {
513 0 : return jami::Manager::instance().removeAccount(accountId, true); // with 'flush' enabled
514 : }
515 :
516 : std::vector<std::string>
517 0 : getAccountList()
518 : {
519 0 : return jami::Manager::instance().getAccountList();
520 : }
521 :
522 : /**
523 : * Send the list of all codecs loaded to the client through DBus.
524 : * Can stay global, as only the active codecs will be set per accounts
525 : */
526 : std::vector<unsigned>
527 0 : getCodecList()
528 : {
529 0 : std::vector<unsigned> list {jami::getSystemCodecContainer()->getSystemCodecInfoIdList(jami::MEDIA_ALL)};
530 0 : if (list.empty())
531 0 : jami::emitSignal<ConfigurationSignal::Error>(CODECS_NOT_LOADED);
532 0 : return list;
533 0 : }
534 :
535 : std::vector<std::string>
536 0 : getSupportedTlsMethod()
537 : {
538 0 : return SIPAccount::getSupportedTlsProtocols();
539 : }
540 :
541 : std::vector<std::string>
542 0 : getSupportedCiphers(const std::string& accountId)
543 : {
544 0 : if (auto sipaccount = jami::Manager::instance().getAccount<SIPAccount>(accountId))
545 0 : return SIPAccount::getSupportedTlsCiphers();
546 0 : JAMI_ERR("SIP account %s doesn't exist", accountId.c_str());
547 0 : return {};
548 : }
549 :
550 : bool
551 0 : setCodecDetails(const std::string& accountId, const unsigned& codecId, const std::map<std::string, std::string>& details)
552 : {
553 0 : auto acc = jami::Manager::instance().getAccount(accountId);
554 0 : if (!acc) {
555 0 : JAMI_ERR("Unable to find account %s. Unable to set codec details", accountId.c_str());
556 0 : return false;
557 : }
558 :
559 0 : auto codec = acc->searchCodecById(codecId, jami::MEDIA_ALL);
560 0 : if (!codec) {
561 0 : JAMI_ERR("Unable to find codec %d", codecId);
562 0 : return false;
563 : }
564 : try {
565 0 : if (codec->mediaType & jami::MEDIA_AUDIO) {
566 0 : if (auto foundCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec)) {
567 0 : foundCodec->setCodecSpecifications(details);
568 0 : jami::emitSignal<ConfigurationSignal::MediaParametersChanged>(accountId);
569 0 : return true;
570 0 : }
571 : }
572 :
573 0 : if (codec->mediaType & jami::MEDIA_VIDEO) {
574 0 : if (auto foundCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec)) {
575 0 : foundCodec->setCodecSpecifications(details);
576 0 : JAMI_WARN("parameters for %s changed ", foundCodec->name.c_str());
577 0 : if (auto call = jami::Manager::instance().getCurrentCall()) {
578 0 : if (call->getVideoCodec() == foundCodec) {
579 0 : JAMI_WARN("%s running. Need to restart encoding", foundCodec->name.c_str());
580 0 : call->restartMediaSender();
581 : }
582 0 : }
583 0 : jami::emitSignal<ConfigurationSignal::MediaParametersChanged>(accountId);
584 0 : return true;
585 0 : }
586 : }
587 0 : } catch (const std::exception& e) {
588 0 : JAMI_ERR("Unable to set codec specifications: %s", e.what());
589 0 : }
590 :
591 0 : return false;
592 0 : }
593 :
594 : std::map<std::string, std::string>
595 0 : getCodecDetails(const std::string& accountId, const unsigned& codecId)
596 : {
597 0 : auto acc = jami::Manager::instance().getAccount(accountId);
598 0 : if (!acc) {
599 0 : JAMI_ERR("Unable to find account %s return default codec details", accountId.c_str());
600 0 : return jami::Account::getDefaultCodecDetails(codecId);
601 : }
602 :
603 0 : auto codec = acc->searchCodecById(codecId, jami::MEDIA_ALL);
604 0 : if (!codec) {
605 0 : jami::emitSignal<ConfigurationSignal::Error>(CODECS_NOT_LOADED);
606 0 : return {};
607 : }
608 :
609 0 : if (codec->mediaType & jami::MEDIA_AUDIO)
610 0 : if (auto foundCodec = std::static_pointer_cast<jami::SystemAudioCodecInfo>(codec))
611 0 : return foundCodec->getCodecSpecifications();
612 :
613 0 : if (codec->mediaType & jami::MEDIA_VIDEO)
614 0 : if (auto foundCodec = std::static_pointer_cast<jami::SystemVideoCodecInfo>(codec))
615 0 : return foundCodec->getCodecSpecifications();
616 :
617 0 : jami::emitSignal<ConfigurationSignal::Error>(CODECS_NOT_LOADED);
618 0 : return {};
619 0 : }
620 :
621 : std::vector<unsigned>
622 0 : getActiveCodecList(const std::string& accountId)
623 : {
624 0 : if (auto acc = jami::Manager::instance().getAccount(accountId))
625 0 : return acc->getActiveCodecs();
626 0 : JAMI_ERR("Unable to find account %s, returning default", accountId.c_str());
627 0 : return jami::Account::getDefaultCodecsId();
628 : }
629 :
630 : void
631 0 : setActiveCodecList(const std::string& accountId, const std::vector<unsigned>& list)
632 : {
633 0 : if (auto acc = jami::Manager::instance().getAccount(accountId)) {
634 0 : acc->setActiveCodecs(list);
635 0 : jami::Manager::instance().saveConfig(acc);
636 : } else {
637 0 : JAMI_ERR("Unable to find account %s", accountId.c_str());
638 0 : }
639 0 : }
640 :
641 : std::vector<std::string>
642 0 : getAudioPluginList()
643 : {
644 0 : return {PCM_DEFAULT, PCM_DMIX_DSNOOP};
645 : }
646 :
647 : void
648 0 : setAudioPlugin(const std::string& audioPlugin)
649 : {
650 0 : return jami::Manager::instance().setAudioPlugin(audioPlugin);
651 : }
652 :
653 : std::vector<std::string>
654 0 : getAudioOutputDeviceList()
655 : {
656 0 : return jami::Manager::instance().getAudioOutputDeviceList();
657 : }
658 :
659 : std::vector<std::string>
660 0 : getAudioInputDeviceList()
661 : {
662 0 : return jami::Manager::instance().getAudioInputDeviceList();
663 : }
664 :
665 : void
666 0 : setAudioOutputDevice(int32_t index)
667 : {
668 0 : return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::PLAYBACK);
669 : }
670 :
671 : void
672 0 : setAudioInputDevice(int32_t index)
673 : {
674 0 : return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::CAPTURE);
675 : }
676 :
677 : void
678 0 : setAudioRingtoneDevice(int32_t index)
679 : {
680 0 : return jami::Manager::instance().setAudioDevice(index, AudioDeviceType::RINGTONE);
681 : }
682 :
683 : std::vector<std::string>
684 0 : getCurrentAudioDevicesIndex()
685 : {
686 0 : return jami::Manager::instance().getCurrentAudioDevicesIndex();
687 : }
688 :
689 : int32_t
690 0 : getAudioInputDeviceIndex(const std::string& name)
691 : {
692 0 : return jami::Manager::instance().getAudioInputDeviceIndex(name);
693 : }
694 :
695 : int32_t
696 0 : getAudioOutputDeviceIndex(const std::string& name)
697 : {
698 0 : return jami::Manager::instance().getAudioOutputDeviceIndex(name);
699 : }
700 :
701 : std::string
702 0 : getCurrentAudioOutputPlugin()
703 : {
704 0 : auto plugin = jami::Manager::instance().getCurrentAudioOutputPlugin();
705 0 : JAMI_DBG("Get audio plugin %s", plugin.c_str());
706 0 : return plugin;
707 0 : }
708 :
709 : std::string
710 0 : getNoiseSuppressState()
711 : {
712 0 : return jami::Manager::instance().getNoiseSuppressState();
713 : }
714 :
715 : void
716 0 : setNoiseSuppressState(const std::string& state)
717 : {
718 0 : jami::Manager::instance().setNoiseSuppressState(state);
719 0 : }
720 :
721 : std::string
722 0 : getEchoCancellationState()
723 : {
724 0 : return jami::Manager::instance().getEchoCancellationState();
725 : }
726 :
727 : void
728 0 : setEchoCancellationState(const std::string& state)
729 : {
730 0 : jami::Manager::instance().setEchoCancellationState(state);
731 0 : }
732 :
733 : bool
734 0 : getVoiceActivityDetectionState()
735 : {
736 0 : return jami::Manager::instance().getVoiceActivityDetectionState();
737 : }
738 :
739 : void
740 0 : setVoiceActivityDetectionState(bool state)
741 : {
742 0 : jami::Manager::instance().setVoiceActivityDetectionState(state);
743 0 : }
744 :
745 : bool
746 0 : isAgcEnabled()
747 : {
748 0 : return jami::Manager::instance().isAGCEnabled();
749 : }
750 :
751 : void
752 0 : setAgcState(bool enabled)
753 : {
754 0 : jami::Manager::instance().setAGCState(enabled);
755 0 : }
756 :
757 : std::string
758 0 : getRecordPath()
759 : {
760 0 : return jami::Manager::instance().audioPreference.getRecordPath();
761 : }
762 :
763 : void
764 0 : setRecordPath(const std::string& recPath)
765 : {
766 0 : jami::Manager::instance().audioPreference.setRecordPath(recPath);
767 0 : }
768 :
769 : bool
770 0 : getIsAlwaysRecording()
771 : {
772 0 : return jami::Manager::instance().getIsAlwaysRecording();
773 : }
774 :
775 : void
776 0 : setIsAlwaysRecording(bool rec)
777 : {
778 0 : jami::Manager::instance().setIsAlwaysRecording(rec);
779 0 : }
780 :
781 : bool
782 0 : getRecordPreview()
783 : {
784 : #ifdef ENABLE_VIDEO
785 0 : return jami::Manager::instance().videoPreferences.getRecordPreview();
786 : #else
787 : return false;
788 : #endif
789 : }
790 :
791 : void
792 0 : setRecordPreview(bool rec)
793 : {
794 : #ifdef ENABLE_VIDEO
795 0 : jami::Manager::instance().videoPreferences.setRecordPreview(rec);
796 0 : jami::Manager::instance().saveConfig();
797 : #endif
798 0 : }
799 :
800 : int32_t
801 0 : getRecordQuality()
802 : {
803 : #ifdef ENABLE_VIDEO
804 0 : return jami::Manager::instance().videoPreferences.getRecordQuality();
805 : #else
806 : return 0;
807 : #endif
808 : }
809 :
810 : void
811 0 : setRecordQuality(int32_t quality)
812 : {
813 : #ifdef ENABLE_VIDEO
814 0 : jami::Manager::instance().videoPreferences.setRecordQuality(quality);
815 0 : jami::Manager::instance().saveConfig();
816 : #endif
817 0 : }
818 :
819 : int32_t
820 0 : getHistoryLimit()
821 : {
822 0 : return jami::Manager::instance().getHistoryLimit();
823 : }
824 :
825 : void
826 0 : setHistoryLimit(int32_t days)
827 : {
828 0 : jami::Manager::instance().setHistoryLimit(days);
829 0 : }
830 :
831 : int32_t
832 0 : getRingingTimeout()
833 : {
834 0 : return static_cast<int32_t>(jami::Manager::instance().getRingingTimeout().count());
835 : }
836 :
837 : void
838 0 : setRingingTimeout(int32_t timeout)
839 : {
840 0 : jami::Manager::instance().setRingingTimeout(std::chrono::seconds(timeout));
841 0 : }
842 :
843 : std::vector<std::string>
844 0 : getSupportedAudioManagers()
845 : {
846 0 : return jami::AudioPreference::getSupportedAudioManagers();
847 : }
848 :
849 : bool
850 0 : setAudioManager(const std::string& api)
851 : {
852 0 : return jami::Manager::instance().setAudioManager(api);
853 : }
854 :
855 : std::string
856 0 : getAudioManager()
857 : {
858 0 : return jami::Manager::instance().getAudioManager();
859 : }
860 :
861 : void
862 0 : setVolume(const std::string& device, double value)
863 : {
864 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver()) {
865 0 : JAMI_DBG("set volume for %s: %f", device.c_str(), value);
866 :
867 0 : if (device == "speaker")
868 0 : audiolayer->setPlaybackGain(value);
869 0 : else if (device == "mic")
870 0 : audiolayer->setCaptureGain(value);
871 :
872 0 : jami::emitSignal<ConfigurationSignal::VolumeChanged>(device, value);
873 : } else {
874 0 : JAMI_ERR("Audio layer not valid while updating volume");
875 0 : }
876 0 : }
877 :
878 : double
879 0 : getVolume(const std::string& device)
880 : {
881 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver()) {
882 0 : if (device == "speaker")
883 0 : return audiolayer->getPlaybackGain();
884 0 : if (device == "mic")
885 0 : return audiolayer->getCaptureGain();
886 0 : }
887 :
888 0 : JAMI_ERR("Audio layer not valid while updating volume");
889 0 : return 0.0;
890 : }
891 :
892 : // FIXME: we should store "muteDtmf" instead of "playDtmf"
893 : // in config and avoid negating like this
894 : bool
895 0 : isDtmfMuted()
896 : {
897 0 : return not jami::Manager::instance().voipPreferences.getPlayDtmf();
898 : }
899 :
900 : void
901 0 : muteDtmf(bool mute)
902 : {
903 0 : jami::Manager::instance().voipPreferences.setPlayDtmf(not mute);
904 0 : }
905 :
906 : bool
907 0 : isCaptureMuted()
908 : {
909 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver())
910 0 : return audiolayer->isCaptureMuted();
911 :
912 0 : JAMI_ERR("Audio layer not valid");
913 0 : return false;
914 : }
915 :
916 : void
917 0 : muteCapture(bool mute)
918 : {
919 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver())
920 0 : return audiolayer->muteCapture(mute);
921 :
922 0 : JAMI_ERR("Audio layer not valid");
923 0 : return;
924 : }
925 :
926 : bool
927 0 : isPlaybackMuted()
928 : {
929 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver())
930 0 : return audiolayer->isPlaybackMuted();
931 :
932 0 : JAMI_ERR("Audio layer not valid");
933 0 : return false;
934 : }
935 :
936 : void
937 0 : mutePlayback(bool mute)
938 : {
939 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver())
940 0 : return audiolayer->mutePlayback(mute);
941 :
942 0 : JAMI_ERR("Audio layer not valid");
943 0 : return;
944 : }
945 :
946 : bool
947 0 : isRingtoneMuted()
948 : {
949 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver())
950 0 : return audiolayer->isRingtoneMuted();
951 :
952 0 : JAMI_ERR("Audio layer not valid");
953 0 : return false;
954 : }
955 :
956 : void
957 0 : muteRingtone(bool mute)
958 : {
959 0 : if (auto audiolayer = jami::Manager::instance().getAudioDriver())
960 0 : return audiolayer->muteRingtone(mute);
961 :
962 0 : JAMI_ERR("Audio layer not valid");
963 0 : return;
964 : }
965 :
966 : void
967 0 : setAccountsOrder(const std::string& order)
968 : {
969 0 : jami::Manager::instance().setAccountsOrder(order);
970 0 : }
971 :
972 : std::string
973 0 : getAddrFromInterfaceName(const std::string& interface)
974 : {
975 0 : return dhtnet::ip_utils::getInterfaceAddr(interface, AF_INET);
976 : }
977 :
978 : std::vector<std::string>
979 0 : getAllIpInterface()
980 : {
981 0 : return dhtnet::ip_utils::getAllIpInterface();
982 : }
983 :
984 : std::vector<std::string>
985 0 : getAllIpInterfaceByName()
986 : {
987 0 : return dhtnet::ip_utils::getAllIpInterfaceByName();
988 : }
989 :
990 : std::vector<std::map<std::string, std::string>>
991 0 : getCredentials(const std::string& accountId)
992 : {
993 0 : if (auto sipaccount = jami::Manager::instance().getAccount<SIPAccount>(accountId))
994 0 : return sipaccount->getCredentials();
995 0 : return {};
996 : }
997 :
998 : void
999 0 : setCredentials(const std::string& accountId, const std::vector<std::map<std::string, std::string>>& details)
1000 : {
1001 0 : if (auto sipaccount = jami::Manager::instance().getAccount<SIPAccount>(accountId)) {
1002 0 : sipaccount->doUnregister();
1003 0 : sipaccount->editConfig([&](jami::SipAccountConfig& config) { config.setCredentials(details); });
1004 0 : sipaccount->loadConfig();
1005 0 : if (sipaccount->isEnabled())
1006 0 : sipaccount->doRegister();
1007 0 : jami::Manager::instance().saveConfig(sipaccount);
1008 0 : }
1009 0 : }
1010 :
1011 : void
1012 0 : connectivityChanged()
1013 : {
1014 0 : JAMI_WARN("received connectivity changed - attempting to re-connect enabled accounts");
1015 :
1016 : // reset the UPnP context
1017 : #if !(defined(TARGET_OS_IOS) && TARGET_OS_IOS)
1018 : try {
1019 0 : jami::Manager::instance().upnpContext()->connectivityChanged();
1020 0 : } catch (std::runtime_error& e) {
1021 0 : JAMI_ERR("UPnP context error: %s", e.what());
1022 0 : }
1023 : #endif
1024 :
1025 0 : for (const auto& account : jami::Manager::instance().getAllAccounts()) {
1026 0 : account->connectivityChanged();
1027 0 : }
1028 0 : }
1029 :
1030 : bool
1031 3 : lookupName(const std::string& account, const std::string& nameserver, const std::string& name)
1032 : {
1033 3 : if (account.empty()) {
1034 : auto cb =
1035 0 : [name](const std::string& regName, const std::string& address, jami::NameDirectory::Response response) {
1036 0 : jami::emitSignal<libjami::ConfigurationSignal::RegisteredNameFound>("",
1037 0 : name,
1038 : (int) response,
1039 : address,
1040 : regName);
1041 0 : };
1042 0 : if (nameserver.empty())
1043 0 : jami::NameDirectory::lookupUri(name, "", cb);
1044 : else
1045 0 : jami::NameDirectory::instance(nameserver).lookupName(name, cb);
1046 0 : return true;
1047 3 : } else if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
1048 3 : acc->lookupName(name);
1049 3 : return true;
1050 3 : }
1051 0 : JAMI_ERROR("lookupName: Unknown account: {}", account);
1052 0 : return false;
1053 : }
1054 :
1055 : bool
1056 3 : lookupAddress(const std::string& account, const std::string& nameserver, const std::string& address)
1057 : {
1058 3 : if (account.empty()) {
1059 0 : jami::NameDirectory::instance(nameserver)
1060 0 : .lookupAddress(address,
1061 0 : [address](const std::string& regName,
1062 : const std::string& addr,
1063 : jami::NameDirectory::Response response) {
1064 0 : jami::emitSignal<libjami::ConfigurationSignal::RegisteredNameFound>("",
1065 0 : address,
1066 : (int) response,
1067 : addr,
1068 : regName);
1069 0 : });
1070 0 : return true;
1071 3 : } else if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
1072 3 : acc->lookupAddress(address);
1073 3 : return true;
1074 3 : }
1075 0 : JAMI_ERROR("lookupAddress: Unknown account: {}", account);
1076 0 : return false;
1077 : }
1078 :
1079 : bool
1080 0 : searchUser(const std::string& account, const std::string& query)
1081 : {
1082 0 : if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
1083 0 : return acc->searchUser(query);
1084 0 : }
1085 0 : return false;
1086 : }
1087 :
1088 : bool
1089 1 : registerName(const std::string& account, const std::string& name, const std::string& scheme, const std::string& password)
1090 : {
1091 1 : if (auto acc = jami::Manager::instance().getAccount<JamiAccount>(account)) {
1092 1 : acc->registerName(name, scheme, password);
1093 1 : return true;
1094 1 : }
1095 0 : JAMI_ERROR("registerName: Unknown account: {}", account);
1096 0 : return false;
1097 : }
1098 :
1099 : void
1100 0 : setPushNotificationToken(const std::string& token)
1101 : {
1102 0 : for (const auto& account : jami::Manager::instance().getAllAccounts()) {
1103 0 : account->setPushNotificationToken(token);
1104 0 : }
1105 0 : }
1106 :
1107 : void
1108 0 : setPushNotificationTopic(const std::string& topic)
1109 : {
1110 0 : for (const auto& account : jami::Manager::instance().getAllAccounts()) {
1111 0 : account->setPushNotificationTopic(topic);
1112 0 : }
1113 0 : }
1114 :
1115 : void
1116 0 : setPushNotificationConfig(const std::map<std::string, std::string>& data)
1117 : {
1118 0 : for (const auto& account : jami::Manager::instance().getAllAccounts()) {
1119 0 : account->setPushNotificationConfig(data);
1120 0 : }
1121 0 : }
1122 :
1123 : void
1124 0 : pushNotificationReceived(const std::string& from, const std::map<std::string, std::string>& data)
1125 : {
1126 : try {
1127 0 : auto it = data.find("to");
1128 0 : if (it != data.end()) {
1129 0 : if (auto account = jami::Manager::instance().getAccount<JamiAccount>(it->second))
1130 0 : account->pushNotificationReceived(from, data);
1131 : }
1132 : #if defined(__ANDROID__) || defined(ANDROID) || defined(__Apple__)
1133 : else {
1134 : for (const auto& sipAccount : jami::Manager::instance().getAllAccounts<SIPAccount>()) {
1135 : sipAccount->pushNotificationReceived(from, data);
1136 : }
1137 : }
1138 : #endif
1139 0 : } catch (const std::exception& e) {
1140 0 : JAMI_ERR("Error processing push notification: %s", e.what());
1141 0 : }
1142 0 : }
1143 :
1144 : bool
1145 0 : isAudioMeterActive(const std::string& id)
1146 : {
1147 0 : return jami::Manager::instance().getRingBufferPool().isAudioMeterActive(id);
1148 : }
1149 :
1150 : void
1151 0 : setAudioMeterState(const std::string& id, bool state)
1152 : {
1153 0 : jami::Manager::instance().getRingBufferPool().setAudioMeterState(id, state);
1154 0 : }
1155 :
1156 : void
1157 0 : setDefaultModerator(const std::string& accountId, const std::string& peerURI, bool state)
1158 : {
1159 0 : jami::Manager::instance().setDefaultModerator(accountId, peerURI, state);
1160 0 : }
1161 :
1162 : std::vector<std::string>
1163 0 : getDefaultModerators(const std::string& accountId)
1164 : {
1165 0 : return jami::Manager::instance().getDefaultModerators(accountId);
1166 : }
1167 :
1168 : void
1169 0 : enableLocalModerators(const std::string& accountId, bool isModEnabled)
1170 : {
1171 0 : jami::Manager::instance().enableLocalModerators(accountId, isModEnabled);
1172 0 : }
1173 :
1174 : bool
1175 0 : isLocalModeratorsEnabled(const std::string& accountId)
1176 : {
1177 0 : return jami::Manager::instance().isLocalModeratorsEnabled(accountId);
1178 : }
1179 :
1180 : void
1181 0 : setAllModerators(const std::string& accountId, bool allModerators)
1182 : {
1183 0 : jami::Manager::instance().setAllModerators(accountId, allModerators);
1184 0 : }
1185 :
1186 : bool
1187 0 : isAllModerators(const std::string& accountId)
1188 : {
1189 0 : return jami::Manager::instance().isAllModerators(accountId);
1190 : }
1191 :
1192 : void
1193 0 : setResourceDirPath(const std::string& resourceDir)
1194 : {
1195 0 : jami::fileutils::set_resource_dir_path(resourceDir);
1196 0 : }
1197 :
1198 : } // namespace libjami
|