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