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