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