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