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