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