1 /*
2 Copyright © 2013 by Maxim Biro <nurupo.contributions@gmail.com>
3 Copyright © 2014-2019 by The qTox Project Contributors
4
5 This file is part of qTox, a Qt-based graphical interface for Tox.
6
7 qTox is libre software: you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation, either version 3 of the License, or
10 (at your option) any later version.
11
12 qTox is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with qTox. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "settings.h"
22 #include "src/core/core.h"
23 #include "src/core/corefile.h"
24 #include "src/nexus.h"
25 #include "src/persistence/profile.h"
26 #include "src/persistence/profilelocker.h"
27 #include "src/persistence/settingsserializer.h"
28 #include "src/persistence/smileypack.h"
29 #include "src/widget/gui.h"
30 #include "src/widget/style.h"
31 #ifdef QTOX_PLATFORM_EXT
32 #include "src/platform/autorun.h"
33 #endif
34 #include "src/ipc.h"
35
36 #include "src/util/compatiblerecursivemutex.h"
37
38 #include <QApplication>
39 #include <QCryptographicHash>
40 #include <QDebug>
41 #include <QDir>
42 #include <QFile>
43 #include <QFont>
44 #include <QList>
45 #include <QMutexLocker>
46 #include <QNetworkProxy>
47 #include <QStandardPaths>
48 #include <QStyleFactory>
49 #include <QThread>
50 #include <QtCore/QCommandLineParser>
51
52 /**
53 * @var QHash<QString, QByteArray> Settings::widgetSettings
54 * @brief Assume all widgets have unique names
55 * @warning Don't use it to save every single thing you want to save, use it
56 * for some general purpose widgets, such as MainWindows or Splitters,
57 * which have widget->saveX() and widget->loadX() methods.
58 */
59
60 const QString Settings::globalSettingsFile = "qtox.ini";
61 Settings* Settings::settings{nullptr};
62 CompatibleRecursiveMutex Settings::bigLock;
63 QThread* Settings::settingsThread{nullptr};
64
Settings()65 Settings::Settings()
66 : loaded(false)
67 , useCustomDhtList{false}
68 , makeToxPortable{false}
69 , currentProfileId(0)
70 {
71 settingsThread = new QThread();
72 settingsThread->setObjectName("qTox Settings");
73 settingsThread->start(QThread::LowPriority);
74 moveToThread(settingsThread);
75 loadGlobal();
76 }
77
~Settings()78 Settings::~Settings()
79 {
80 sync();
81 settingsThread->exit(0);
82 settingsThread->wait();
83 delete settingsThread;
84 }
85
86 /**
87 * @brief Returns the singleton instance.
88 */
getInstance()89 Settings& Settings::getInstance()
90 {
91 if (!settings)
92 settings = new Settings();
93
94 return *settings;
95 }
96
destroyInstance()97 void Settings::destroyInstance()
98 {
99 delete settings;
100 settings = nullptr;
101 }
102
loadGlobal()103 void Settings::loadGlobal()
104 {
105 QMutexLocker locker{&bigLock};
106
107 if (loaded)
108 return;
109
110 createSettingsDir();
111
112 makeToxPortable = Settings::isToxPortable();
113
114 QDir dir(getSettingsDirPath());
115 QString filePath = dir.filePath(globalSettingsFile);
116
117 // If no settings file exist -- use the default one
118 if (!QFile(filePath).exists()) {
119 qDebug() << "No settings file found, using defaults";
120 filePath = ":/conf/" + globalSettingsFile;
121 }
122
123 qDebug() << "Loading settings from " + filePath;
124
125 QSettings s(filePath, QSettings::IniFormat);
126 s.setIniCodec("UTF-8");
127
128 s.beginGroup("Login");
129 {
130 autoLogin = s.value("autoLogin", false).toBool();
131 }
132 s.endGroup();
133
134 s.beginGroup("General");
135 {
136 translation = s.value("translation", "en").toString();
137 showSystemTray = s.value("showSystemTray", true).toBool();
138 autostartInTray = s.value("autostartInTray", false).toBool();
139 closeToTray = s.value("closeToTray", false).toBool();
140 if (currentProfile.isEmpty()) {
141 currentProfile = s.value("currentProfile", "").toString();
142 currentProfileId = makeProfileId(currentProfile);
143 }
144 autoAwayTime = s.value("autoAwayTime", 10).toInt();
145 checkUpdates = s.value("checkUpdates", true).toBool();
146 // note: notifySound and busySound UI elements are now under UI settings
147 // page, but kept under General in settings file to be backwards compatible
148 notifySound = s.value("notifySound", true).toBool();
149 notifyHide = s.value("notifyHide", false).toBool();
150 busySound = s.value("busySound", false).toBool();
151 autoSaveEnabled = s.value("autoSaveEnabled", false).toBool();
152 globalAutoAcceptDir = s.value("globalAutoAcceptDir",
153 QStandardPaths::locate(QStandardPaths::HomeLocation, QString(),
154 QStandardPaths::LocateDirectory))
155 .toString();
156 autoAcceptMaxSize =
157 static_cast<size_t>(s.value("autoAcceptMaxSize", 20 << 20 /*20 MB*/).toLongLong());
158 stylePreference = static_cast<StyleType>(s.value("stylePreference", 1).toInt());
159 }
160 s.endGroup();
161
162 s.beginGroup("Advanced");
163 {
164 makeToxPortable = s.value("makeToxPortable", false).toBool();
165 enableIPv6 = s.value("enableIPv6", true).toBool();
166 forceTCP = s.value("forceTCP", false).toBool();
167 enableLanDiscovery = s.value("enableLanDiscovery", true).toBool();
168 }
169 s.endGroup();
170
171 s.beginGroup("Widgets");
172 {
173 QList<QString> objectNames = s.childKeys();
174 for (const QString& name : objectNames)
175 widgetSettings[name] = s.value(name).toByteArray();
176 }
177 s.endGroup();
178
179 s.beginGroup("GUI");
180 {
181 showWindow = s.value("showWindow", true).toBool();
182 notify = s.value("notify", true).toBool();
183 desktopNotify = s.value("desktopNotify", true).toBool();
184 groupAlwaysNotify = s.value("groupAlwaysNotify", true).toBool();
185 groupchatPosition = s.value("groupchatPosition", true).toBool();
186 separateWindow = s.value("separateWindow", false).toBool();
187 dontGroupWindows = s.value("dontGroupWindows", false).toBool();
188 showIdenticons = s.value("showIdenticons", true).toBool();
189
190 const QString DEFAULT_SMILEYS = ":/smileys/emojione/emoticons.xml";
191 smileyPack = s.value("smileyPack", DEFAULT_SMILEYS).toString();
192 if (!QFile::exists(smileyPack)) {
193 smileyPack = DEFAULT_SMILEYS;
194 }
195
196 emojiFontPointSize = s.value("emojiFontPointSize", 24).toInt();
197 firstColumnHandlePos = s.value("firstColumnHandlePos", 50).toInt();
198 secondColumnHandlePosFromRight = s.value("secondColumnHandlePosFromRight", 50).toInt();
199 timestampFormat = s.value("timestampFormat", "hh:mm:ss").toString();
200 dateFormat = s.value("dateFormat", "yyyy-MM-dd").toString();
201 minimizeOnClose = s.value("minimizeOnClose", false).toBool();
202 minimizeToTray = s.value("minimizeToTray", false).toBool();
203 lightTrayIcon = s.value("lightTrayIcon", false).toBool();
204 useEmoticons = s.value("useEmoticons", true).toBool();
205 statusChangeNotificationEnabled = s.value("statusChangeNotificationEnabled", false).toBool();
206 spellCheckingEnabled = s.value("spellCheckingEnabled", true).toBool();
207 themeColor = s.value("themeColor", 0).toInt();
208 style = s.value("style", "").toString();
209 if (style == "") // Default to Fusion if available, otherwise no style
210 {
211 if (QStyleFactory::keys().contains("Fusion"))
212 style = "Fusion";
213 else
214 style = "None";
215 }
216 nameColors = s.value("nameColors", false).toBool();
217 }
218 s.endGroup();
219
220 s.beginGroup("Chat");
221 {
222 chatMessageFont = s.value("chatMessageFont", Style::getFont(Style::Big)).value<QFont>();
223 }
224 s.endGroup();
225
226 s.beginGroup("State");
227 {
228 windowGeometry = s.value("windowGeometry", QByteArray()).toByteArray();
229 windowState = s.value("windowState", QByteArray()).toByteArray();
230 splitterState = s.value("splitterState", QByteArray()).toByteArray();
231 dialogGeometry = s.value("dialogGeometry", QByteArray()).toByteArray();
232 dialogSplitterState = s.value("dialogSplitterState", QByteArray()).toByteArray();
233 dialogSettingsGeometry = s.value("dialogSettingsGeometry", QByteArray()).toByteArray();
234 }
235 s.endGroup();
236
237 s.beginGroup("Audio");
238 {
239 inDev = s.value("inDev", "").toString();
240 audioInDevEnabled = s.value("audioInDevEnabled", true).toBool();
241 outDev = s.value("outDev", "").toString();
242 audioOutDevEnabled = s.value("audioOutDevEnabled", true).toBool();
243 audioInGainDecibel = s.value("inGain", 0).toReal();
244 audioThreshold = s.value("audioThreshold", 0).toReal();
245 outVolume = s.value("outVolume", 100).toInt();
246 enableTestSound = s.value("enableTestSound", true).toBool();
247 audioBitrate = s.value("audioBitrate", 64).toInt();
248 }
249 s.endGroup();
250
251 s.beginGroup("Video");
252 {
253 videoDev = s.value("videoDev", "").toString();
254 camVideoRes = s.value("camVideoRes", QRect()).toRect();
255 screenRegion = s.value("screenRegion", QRect()).toRect();
256 screenGrabbed = s.value("screenGrabbed", false).toBool();
257 camVideoFPS = static_cast<quint16>(s.value("camVideoFPS", 0).toUInt());
258 }
259 s.endGroup();
260
261 loaded = true;
262 }
263
isToxPortable()264 bool Settings::isToxPortable()
265 {
266 QString localSettingsPath = qApp->applicationDirPath() + QDir::separator() + globalSettingsFile;
267 if (!QFile(localSettingsPath).exists()) {
268 return false;
269 }
270 QSettings ps(localSettingsPath, QSettings::IniFormat);
271 ps.setIniCodec("UTF-8");
272 ps.beginGroup("Advanced");
273 bool result = ps.value("makeToxPortable", false).toBool();
274 ps.endGroup();
275 return result;
276 }
277
updateProfileData(Profile * profile,const QCommandLineParser * parser)278 void Settings::updateProfileData(Profile* profile, const QCommandLineParser* parser)
279 {
280 QMutexLocker locker{&bigLock};
281
282 if (profile == nullptr) {
283 qWarning() << QString("Could not load new settings (profile change to nullptr)");
284 return;
285 }
286 setCurrentProfile(profile->getName());
287 saveGlobal();
288 loadPersonal(profile->getName(), profile->getPasskey());
289 if (parser) {
290 applyCommandLineOptions(*parser);
291 }
292 }
293
294 /**
295 * Verifies that commandline proxy settings are at least reasonable. Does not verify provided IP
296 * or hostname addresses are valid. Code duplication with Settings::applyCommandLineOptions, which
297 * also verifies arguments, should be removed in a future refactor.
298 * @param parser QCommandLineParser instance
299 */
verifyProxySettings(const QCommandLineParser & parser)300 bool Settings::verifyProxySettings(const QCommandLineParser& parser)
301 {
302 QString IPv6SettingString = parser.value("I").toLower();
303 QString LANSettingString = parser.value("L").toLower();
304 QString UDPSettingString = parser.value("U").toLower();
305 QString proxySettingString = parser.value("proxy").toLower();
306 QStringList proxySettingStrings = proxySettingString.split(":");
307
308 const QString SOCKS5 = QStringLiteral("socks5");
309 const QString HTTP = QStringLiteral("http");
310 const QString NONE = QStringLiteral("none");
311 const QString ON = QStringLiteral("on");
312 const QString OFF = QStringLiteral("off");
313
314 // Check for incompatible settings
315 bool activeProxyType = false;
316
317 if (parser.isSet("P")) {
318 activeProxyType = proxySettingStrings[0] == SOCKS5 || proxySettingStrings[0] == HTTP;
319 }
320
321 if (parser.isSet("I")) {
322 if (!(IPv6SettingString == ON || IPv6SettingString == OFF)) {
323 qCritical() << "Unable to parse IPv6 setting.";
324 return false;
325 }
326 }
327
328 if (parser.isSet("U")) {
329 if (!(UDPSettingString == ON || UDPSettingString == OFF)) {
330 qCritical() << "Unable to parse UDP setting.";
331 return false;
332 }
333 }
334
335 if (parser.isSet("L")) {
336 if (!(LANSettingString == ON || LANSettingString == OFF)) {
337 qCritical() << "Unable to parse LAN setting.";
338 return false;
339 }
340 }
341 if (activeProxyType && UDPSettingString == ON) {
342 qCritical() << "Cannot set UDP on with proxy.";
343 return false;
344 }
345
346 if (activeProxyType && LANSettingString == ON) {
347 qCritical() << "Cannot set LAN discovery on with proxy.";
348 return false;
349 }
350
351 if (LANSettingString == ON && UDPSettingString == OFF) {
352 qCritical() << "Incompatible UDP/LAN settings.";
353 return false;
354 }
355
356 if (parser.isSet("P")) {
357 if (proxySettingStrings[0] == NONE) {
358 // slightly lazy check here, accepting 'NONE[:.*]' is fine since no other
359 // arguments will be investigated when proxy settings are applied.
360 return true;
361 }
362 // Since the first argument isn't 'none', verify format of remaining arguments
363 if (proxySettingStrings.size() != 3) {
364 qCritical() << "Invalid number of proxy arguments.";
365 return false;
366 }
367
368 if (!(proxySettingStrings[0] == SOCKS5 || proxySettingStrings[0] == HTTP)) {
369 qCritical() << "Unable to parse proxy type.";
370 return false;
371 }
372
373 // TODO(Kriby): Sanity check IPv4/IPv6 addresses/hostnames?
374
375 int portNumber = proxySettingStrings[2].toInt();
376 if (!(portNumber > 0 && portNumber < 65536)) {
377 qCritical() << "Invalid port number range.";
378 }
379 }
380 return true;
381 }
382
383 /**
384 * Applies command line options on top of loaded settings. Fails without changes if attempting to
385 * apply contradicting settings.
386 * @param parser QCommandLineParser instance
387 * @return Success indicator (success = true)
388 */
applyCommandLineOptions(const QCommandLineParser & parser)389 bool Settings::applyCommandLineOptions(const QCommandLineParser& parser)
390 {
391 if (!verifyProxySettings(parser)) {
392 return false;
393 };
394
395 QString IPv6Setting = parser.value("I").toUpper();
396 QString LANSetting = parser.value("L").toUpper();
397 QString UDPSetting = parser.value("U").toUpper();
398 QString proxySettingString = parser.value("proxy").toUpper();
399 QStringList proxySettings = proxySettingString.split(":");
400
401 const QString SOCKS5 = QStringLiteral("SOCKS5");
402 const QString HTTP = QStringLiteral("HTTP");
403 const QString NONE = QStringLiteral("NONE");
404 const QString ON = QStringLiteral("ON");
405 const QString OFF = QStringLiteral("OFF");
406
407
408 if (parser.isSet("I")) {
409 enableIPv6 = IPv6Setting == ON;
410 qDebug() << QString("Setting IPv6 %1.").arg(IPv6Setting);
411 }
412
413 if (parser.isSet("P")) {
414 qDebug() << QString("Setting proxy type to %1.").arg(proxySettings[0]);
415
416 quint16 portNumber = 0;
417 QString address = "";
418
419 if (proxySettings[0] == NONE) {
420 proxyType = ICoreSettings::ProxyType::ptNone;
421 } else {
422 if (proxySettings[0] == SOCKS5) {
423 proxyType = ICoreSettings::ProxyType::ptSOCKS5;
424 } else if (proxySettings[0] == HTTP) {
425 proxyType = ICoreSettings::ProxyType::ptHTTP;
426 } else {
427 qCritical() << "Failed to set valid proxy type";
428 assert(false); // verifyProxySettings should've made this impossible
429 }
430
431 forceTCP = true;
432 enableLanDiscovery = false;
433
434 address = proxySettings[1];
435 portNumber = static_cast<quint16>(proxySettings[2].toInt());
436 }
437
438
439 proxyAddr = address;
440 qDebug() << QString("Setting proxy address to %1.").arg(address);
441 proxyPort = portNumber;
442 qDebug() << QString("Setting port number to %1.").arg(portNumber);
443 }
444
445 if (parser.isSet("U")) {
446 bool shouldForceTCP = UDPSetting == OFF;
447 if (!shouldForceTCP && proxyType != ICoreSettings::ProxyType::ptNone) {
448 qDebug() << "Cannot use UDP with proxy; disable proxy explicitly with '-P none'.";
449 } else {
450 forceTCP = shouldForceTCP;
451 qDebug() << QString("Setting UDP %1.").arg(UDPSetting);
452 }
453
454 // LANSetting == ON is caught by verifyProxySettings, the OFF check removes needless debug
455 if (shouldForceTCP && !(LANSetting == OFF) && enableLanDiscovery) {
456 qDebug() << "Cannot perform LAN discovery without UDP; disabling LAN discovery.";
457 enableLanDiscovery = false;
458 }
459 }
460
461 if (parser.isSet("L")) {
462 bool shouldEnableLAN = LANSetting == ON;
463
464 if (shouldEnableLAN && proxyType != ICoreSettings::ProxyType::ptNone) {
465 qDebug()
466 << "Cannot use LAN discovery with proxy; disable proxy explicitly with '-P none'.";
467 } else if (shouldEnableLAN && forceTCP) {
468 qDebug() << "Cannot use LAN discovery without UDP; enable UDP explicitly with '-U on'.";
469 } else {
470 enableLanDiscovery = shouldEnableLAN;
471 qDebug() << QString("Setting LAN Discovery %1.").arg(LANSetting);
472 }
473 }
474 return true;
475 }
476
loadPersonal(QString profileName,const ToxEncrypt * passKey)477 void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey)
478 {
479 QMutexLocker locker{&bigLock};
480
481 QDir dir(getSettingsDirPath());
482 QString filePath = dir.filePath(globalSettingsFile);
483
484 // load from a profile specific friend data list if possible
485 QString tmp = dir.filePath(profileName + ".ini");
486 if (QFile(tmp).exists()) // otherwise, filePath remains the global file
487 filePath = tmp;
488
489 qDebug() << "Loading personal settings from" << filePath;
490
491 SettingsSerializer ps(filePath, passKey);
492 ps.load();
493 friendLst.clear();
494
495 ps.beginGroup("Privacy");
496 {
497 typingNotification = ps.value("typingNotification", true).toBool();
498 enableLogging = ps.value("enableLogging", true).toBool();
499 blackList = ps.value("blackList").toString().split('\n');
500 }
501 ps.endGroup();
502
503 ps.beginGroup("Friends");
504 {
505 int size = ps.beginReadArray("Friend");
506 friendLst.reserve(size);
507 for (int i = 0; i < size; i++) {
508 ps.setArrayIndex(i);
509 friendProp fp{ps.value("addr").toString()};
510 fp.alias = ps.value("alias").toString();
511 fp.note = ps.value("note").toString();
512 fp.autoAcceptDir = ps.value("autoAcceptDir").toString();
513
514 if (fp.autoAcceptDir == "")
515 fp.autoAcceptDir = ps.value("autoAccept").toString();
516
517 fp.autoAcceptCall =
518 Settings::AutoAcceptCallFlags(QFlag(ps.value("autoAcceptCall", 0).toInt()));
519 fp.autoGroupInvite = ps.value("autoGroupInvite").toBool();
520 fp.circleID = ps.value("circle", -1).toInt();
521
522 if (getEnableLogging())
523 fp.activity = ps.value("activity", QDateTime()).toDateTime();
524 friendLst.insert(ToxId(fp.addr).getPublicKey().getByteArray(), fp);
525 }
526 ps.endArray();
527 }
528 ps.endGroup();
529
530 ps.beginGroup("Requests");
531 {
532 int size = ps.beginReadArray("Request");
533 friendRequests.clear();
534 friendRequests.reserve(size);
535 for (int i = 0; i < size; i++) {
536 ps.setArrayIndex(i);
537 Request request;
538 request.address = ps.value("addr").toString();
539 request.message = ps.value("message").toString();
540 request.read = ps.value("read").toBool();
541 friendRequests.push_back(request);
542 }
543 ps.endArray();
544 }
545 ps.endGroup();
546
547 ps.beginGroup("GUI");
548 {
549 compactLayout = ps.value("compactLayout", true).toBool();
550 sortingMode = static_cast<FriendListSortingMode>(
551 ps.value("friendSortingMethod", static_cast<int>(FriendListSortingMode::Name)).toInt());
552 }
553 ps.endGroup();
554
555 ps.beginGroup("Proxy");
556 {
557 proxyType = static_cast<ProxyType>(ps.value("proxyType", 0 /* ProxyType::None */).toInt());
558 proxyType = fixInvalidProxyType(proxyType);
559 proxyAddr = ps.value("proxyAddr", proxyAddr).toString();
560 proxyPort = static_cast<quint16>(ps.value("proxyPort", proxyPort).toUInt());
561 }
562 ps.endGroup();
563
564 ps.beginGroup("Circles");
565 {
566 int size = ps.beginReadArray("Circle");
567 circleLst.clear();
568 circleLst.reserve(size);
569 for (int i = 0; i < size; i++) {
570 ps.setArrayIndex(i);
571 circleProp cp;
572 cp.name = ps.value("name").toString();
573 cp.expanded = ps.value("expanded", true).toBool();
574 circleLst.push_back(cp);
575 }
576 ps.endArray();
577 }
578 ps.endGroup();
579 }
580
resetToDefault()581 void Settings::resetToDefault()
582 {
583 // To stop saving
584 loaded = false;
585
586 // Remove file with profile settings
587 QDir dir(getSettingsDirPath());
588 Profile* profile = Nexus::getProfile();
589 QString localPath = dir.filePath(profile->getName() + ".ini");
590 QFile local(localPath);
591 if (local.exists())
592 local.remove();
593 }
594
595 /**
596 * @brief Asynchronous, saves the global settings.
597 */
saveGlobal()598 void Settings::saveGlobal()
599 {
600 if (QThread::currentThread() != settingsThread)
601 return (void)QMetaObject::invokeMethod(&getInstance(), "saveGlobal");
602
603 QMutexLocker locker{&bigLock};
604 if (!loaded)
605 return;
606
607 QString path = getSettingsDirPath() + globalSettingsFile;
608 qDebug() << "Saving global settings at " + path;
609
610 QSettings s(path, QSettings::IniFormat);
611 s.setIniCodec("UTF-8");
612
613 s.clear();
614
615 s.beginGroup("Login");
616 {
617 s.setValue("autoLogin", autoLogin);
618 }
619 s.endGroup();
620
621 s.beginGroup("General");
622 {
623 s.setValue("translation", translation);
624 s.setValue("showSystemTray", showSystemTray);
625 s.setValue("autostartInTray", autostartInTray);
626 s.setValue("closeToTray", closeToTray);
627 s.setValue("currentProfile", currentProfile);
628 s.setValue("autoAwayTime", autoAwayTime);
629 s.setValue("checkUpdates", checkUpdates);
630 s.setValue("notifySound", notifySound);
631 s.setValue("notifyHide", notifyHide);
632 s.setValue("busySound", busySound);
633 s.setValue("autoSaveEnabled", autoSaveEnabled);
634 s.setValue("autoAcceptMaxSize", static_cast<qlonglong>(autoAcceptMaxSize));
635 s.setValue("globalAutoAcceptDir", globalAutoAcceptDir);
636 s.setValue("stylePreference", static_cast<int>(stylePreference));
637 }
638 s.endGroup();
639
640 s.beginGroup("Advanced");
641 {
642 s.setValue("makeToxPortable", makeToxPortable);
643 s.setValue("enableIPv6", enableIPv6);
644 s.setValue("forceTCP", forceTCP);
645 s.setValue("enableLanDiscovery", enableLanDiscovery);
646 s.setValue("dbSyncType", static_cast<int>(dbSyncType));
647 }
648 s.endGroup();
649
650 s.beginGroup("Widgets");
651 {
652 const QList<QString> widgetNames = widgetSettings.keys();
653 for (const QString& name : widgetNames)
654 s.setValue(name, widgetSettings.value(name));
655 }
656 s.endGroup();
657
658 s.beginGroup("GUI");
659 {
660 s.setValue("showWindow", showWindow);
661 s.setValue("notify", notify);
662 s.setValue("desktopNotify", desktopNotify);
663 s.setValue("groupAlwaysNotify", groupAlwaysNotify);
664 s.setValue("separateWindow", separateWindow);
665 s.setValue("dontGroupWindows", dontGroupWindows);
666 s.setValue("groupchatPosition", groupchatPosition);
667 s.setValue("showIdenticons", showIdenticons);
668
669 s.setValue("smileyPack", smileyPack);
670 s.setValue("emojiFontPointSize", emojiFontPointSize);
671 s.setValue("firstColumnHandlePos", firstColumnHandlePos);
672 s.setValue("secondColumnHandlePosFromRight", secondColumnHandlePosFromRight);
673 s.setValue("timestampFormat", timestampFormat);
674 s.setValue("dateFormat", dateFormat);
675 s.setValue("minimizeOnClose", minimizeOnClose);
676 s.setValue("minimizeToTray", minimizeToTray);
677 s.setValue("lightTrayIcon", lightTrayIcon);
678 s.setValue("useEmoticons", useEmoticons);
679 s.setValue("themeColor", themeColor);
680 s.setValue("style", style);
681 s.setValue("nameColors", nameColors);
682 s.setValue("statusChangeNotificationEnabled", statusChangeNotificationEnabled);
683 s.setValue("spellCheckingEnabled", spellCheckingEnabled);
684 }
685 s.endGroup();
686
687 s.beginGroup("Chat");
688 {
689 s.setValue("chatMessageFont", chatMessageFont);
690 }
691 s.endGroup();
692
693 s.beginGroup("State");
694 {
695 s.setValue("windowGeometry", windowGeometry);
696 s.setValue("windowState", windowState);
697 s.setValue("splitterState", splitterState);
698 s.setValue("dialogGeometry", dialogGeometry);
699 s.setValue("dialogSplitterState", dialogSplitterState);
700 s.setValue("dialogSettingsGeometry", dialogSettingsGeometry);
701 }
702 s.endGroup();
703
704 s.beginGroup("Audio");
705 {
706 s.setValue("inDev", inDev);
707 s.setValue("audioInDevEnabled", audioInDevEnabled);
708 s.setValue("outDev", outDev);
709 s.setValue("audioOutDevEnabled", audioOutDevEnabled);
710 s.setValue("inGain", audioInGainDecibel);
711 s.setValue("audioThreshold", audioThreshold);
712 s.setValue("outVolume", outVolume);
713 s.setValue("enableTestSound", enableTestSound);
714 s.setValue("audioBitrate", audioBitrate);
715 }
716 s.endGroup();
717
718 s.beginGroup("Video");
719 {
720 s.setValue("videoDev", videoDev);
721 s.setValue("camVideoRes", camVideoRes);
722 s.setValue("camVideoFPS", camVideoFPS);
723 s.setValue("screenRegion", screenRegion);
724 s.setValue("screenGrabbed", screenGrabbed);
725 }
726 s.endGroup();
727 }
728
729 /**
730 * @brief Asynchronous, saves the current profile.
731 */
savePersonal()732 void Settings::savePersonal()
733 {
734 savePersonal(Nexus::getProfile());
735 }
736
737 /**
738 * @brief Asynchronous, saves the profile.
739 * @param profile Profile to save.
740 */
savePersonal(Profile * profile)741 void Settings::savePersonal(Profile* profile)
742 {
743 if (!profile) {
744 qDebug() << "Could not save personal settings because there is no active profile";
745 return;
746 }
747 if (QThread::currentThread() != settingsThread)
748 return (void)QMetaObject::invokeMethod(&getInstance(), "savePersonal",
749 Q_ARG(Profile*, profile));
750 savePersonal(profile->getName(), profile->getPasskey());
751 }
752
savePersonal(QString profileName,const ToxEncrypt * passkey)753 void Settings::savePersonal(QString profileName, const ToxEncrypt* passkey)
754 {
755 QMutexLocker locker{&bigLock};
756 if (!loaded)
757 return;
758
759 QString path = getSettingsDirPath() + profileName + ".ini";
760
761 qDebug() << "Saving personal settings at " << path;
762
763 SettingsSerializer ps(path, passkey);
764 ps.beginGroup("Friends");
765 {
766 ps.beginWriteArray("Friend", friendLst.size());
767 int index = 0;
768 for (auto& frnd : friendLst) {
769 ps.setArrayIndex(index);
770 ps.setValue("addr", frnd.addr);
771 ps.setValue("alias", frnd.alias);
772 ps.setValue("note", frnd.note);
773 ps.setValue("autoAcceptDir", frnd.autoAcceptDir);
774 ps.setValue("autoAcceptCall", static_cast<int>(frnd.autoAcceptCall));
775 ps.setValue("autoGroupInvite", frnd.autoGroupInvite);
776 ps.setValue("circle", frnd.circleID);
777
778 if (getEnableLogging())
779 ps.setValue("activity", frnd.activity);
780
781 ++index;
782 }
783 ps.endArray();
784 }
785 ps.endGroup();
786
787 ps.beginGroup("Requests");
788 {
789 ps.beginWriteArray("Request", friendRequests.size());
790 int index = 0;
791 for (auto& request : friendRequests) {
792 ps.setArrayIndex(index);
793 ps.setValue("addr", request.address);
794 ps.setValue("message", request.message);
795 ps.setValue("read", request.read);
796
797 ++index;
798 }
799 ps.endArray();
800 }
801 ps.endGroup();
802
803 ps.beginGroup("GUI");
804 {
805 ps.setValue("compactLayout", compactLayout);
806 ps.setValue("friendSortingMethod", static_cast<int>(sortingMode));
807 }
808 ps.endGroup();
809
810 ps.beginGroup("Proxy");
811 {
812 ps.setValue("proxyType", static_cast<int>(proxyType));
813 ps.setValue("proxyAddr", proxyAddr);
814 ps.setValue("proxyPort", proxyPort);
815 }
816 ps.endGroup();
817
818 ps.beginGroup("Circles");
819 {
820 ps.beginWriteArray("Circle", circleLst.size());
821 int index = 0;
822 for (auto& circle : circleLst) {
823 ps.setArrayIndex(index);
824 ps.setValue("name", circle.name);
825 ps.setValue("expanded", circle.expanded);
826 ++index;
827 }
828 ps.endArray();
829 }
830 ps.endGroup();
831
832 ps.beginGroup("Privacy");
833 {
834 ps.setValue("typingNotification", typingNotification);
835 ps.setValue("enableLogging", enableLogging);
836 ps.setValue("blackList", blackList.join('\n'));
837 }
838 ps.endGroup();
839 ps.save();
840 }
841
makeProfileId(const QString & profile)842 uint32_t Settings::makeProfileId(const QString& profile)
843 {
844 QByteArray data = QCryptographicHash::hash(profile.toUtf8(), QCryptographicHash::Md5);
845 const uint32_t* dwords = reinterpret_cast<const uint32_t*>(data.constData());
846 return dwords[0] ^ dwords[1] ^ dwords[2] ^ dwords[3];
847 }
848
849 /**
850 * @brief Get path to directory, where the settings files are stored.
851 * @return Path to settings directory, ends with a directory separator.
852 */
getSettingsDirPath() const853 QString Settings::getSettingsDirPath() const
854 {
855 QMutexLocker locker{&bigLock};
856 if (makeToxPortable)
857 return qApp->applicationDirPath() + QDir::separator();
858
859 // workaround for https://bugreports.qt-project.org/browse/QTBUG-38845
860 #ifdef Q_OS_WIN
861 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
862 + QDir::separator() + "AppData" + QDir::separator() + "Roaming"
863 + QDir::separator() + "tox")
864 + QDir::separator();
865 #elif defined(Q_OS_OSX)
866 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
867 + QDir::separator() + "Library" + QDir::separator()
868 + "Application Support" + QDir::separator() + "Tox")
869 + QDir::separator();
870 #else
871 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
872 + QDir::separator() + "tox")
873 + QDir::separator();
874 #endif
875 }
876
877 /**
878 * @brief Get path to directory, where the application data are stored.
879 * @return Path to application data, ends with a directory separator.
880 */
getAppDataDirPath() const881 QString Settings::getAppDataDirPath() const
882 {
883 QMutexLocker locker{&bigLock};
884 if (makeToxPortable)
885 return qApp->applicationDirPath() + QDir::separator();
886
887 // workaround for https://bugreports.qt-project.org/browse/QTBUG-38845
888 #ifdef Q_OS_WIN
889 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
890 + QDir::separator() + "AppData" + QDir::separator() + "Roaming"
891 + QDir::separator() + "tox")
892 + QDir::separator();
893 #elif defined(Q_OS_OSX)
894 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
895 + QDir::separator() + "Library" + QDir::separator()
896 + "Application Support" + QDir::separator() + "Tox")
897 + QDir::separator();
898 #else
899 /*
900 * TODO: Change QStandardPaths::DataLocation to AppDataLocation when upgrate Qt to 5.4+
901 * For now we need support Qt 5.3, so we use deprecated DataLocation
902 * BTW, it's not a big deal since for linux AppDataLocation and DataLocation are equal
903 */
904 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation))
905 + QDir::separator();
906 #endif
907 }
908
909 /**
910 * @brief Get path to directory, where the application cache are stored.
911 * @return Path to application cache, ends with a directory separator.
912 */
getAppCacheDirPath() const913 QString Settings::getAppCacheDirPath() const
914 {
915 QMutexLocker locker{&bigLock};
916 if (makeToxPortable)
917 return qApp->applicationDirPath() + QDir::separator();
918
919 // workaround for https://bugreports.qt-project.org/browse/QTBUG-38845
920 #ifdef Q_OS_WIN
921 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
922 + QDir::separator() + "AppData" + QDir::separator() + "Roaming"
923 + QDir::separator() + "tox")
924 + QDir::separator();
925 #elif defined(Q_OS_OSX)
926 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation)
927 + QDir::separator() + "Library" + QDir::separator()
928 + "Application Support" + QDir::separator() + "Tox")
929 + QDir::separator();
930 #else
931 return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation))
932 + QDir::separator();
933 #endif
934 }
935
getEnableTestSound() const936 bool Settings::getEnableTestSound() const
937 {
938 QMutexLocker locker{&bigLock};
939 return enableTestSound;
940 }
941
setEnableTestSound(bool newValue)942 void Settings::setEnableTestSound(bool newValue)
943 {
944 QMutexLocker locker{&bigLock};
945
946 if (newValue != enableTestSound) {
947 enableTestSound = newValue;
948 emit enableTestSoundChanged(enableTestSound);
949 }
950 }
951
getEnableIPv6() const952 bool Settings::getEnableIPv6() const
953 {
954 QMutexLocker locker{&bigLock};
955 return enableIPv6;
956 }
957
setEnableIPv6(bool enabled)958 void Settings::setEnableIPv6(bool enabled)
959 {
960 QMutexLocker locker{&bigLock};
961
962 if (enabled != enableIPv6) {
963 enableIPv6 = enabled;
964 emit enableIPv6Changed(enableIPv6);
965 }
966 }
967
getMakeToxPortable() const968 bool Settings::getMakeToxPortable() const
969 {
970 QMutexLocker locker{&bigLock};
971 return makeToxPortable;
972 }
973
setMakeToxPortable(bool newValue)974 void Settings::setMakeToxPortable(bool newValue)
975 {
976 QMutexLocker locker{&bigLock};
977
978 if (newValue != makeToxPortable) {
979 QFile(getSettingsDirPath() + globalSettingsFile).remove();
980 makeToxPortable = newValue;
981 saveGlobal();
982
983 emit makeToxPortableChanged(makeToxPortable);
984 }
985 }
986
getAutorun() const987 bool Settings::getAutorun() const
988 {
989 QMutexLocker locker{&bigLock};
990
991 #ifdef QTOX_PLATFORM_EXT
992 return Platform::getAutorun();
993 #else
994 return false;
995 #endif
996 }
997
setAutorun(bool newValue)998 void Settings::setAutorun(bool newValue)
999 {
1000 #ifdef QTOX_PLATFORM_EXT
1001 QMutexLocker locker{&bigLock};
1002
1003 bool autorun = Platform::getAutorun();
1004
1005 if (newValue != autorun) {
1006 Platform::setAutorun(newValue);
1007 emit autorunChanged(autorun);
1008 }
1009 #else
1010 Q_UNUSED(newValue);
1011 #endif
1012 }
1013
getAutostartInTray() const1014 bool Settings::getAutostartInTray() const
1015 {
1016 QMutexLocker locker{&bigLock};
1017 return autostartInTray;
1018 }
1019
getStyle() const1020 QString Settings::getStyle() const
1021 {
1022 QMutexLocker locker{&bigLock};
1023 return style;
1024 }
1025
setStyle(const QString & newStyle)1026 void Settings::setStyle(const QString& newStyle)
1027 {
1028 QMutexLocker locker{&bigLock};
1029
1030 if (newStyle != style) {
1031 style = newStyle;
1032 emit styleChanged(style);
1033 }
1034 }
1035
getShowSystemTray() const1036 bool Settings::getShowSystemTray() const
1037 {
1038 QMutexLocker locker{&bigLock};
1039 return showSystemTray;
1040 }
1041
setShowSystemTray(bool newValue)1042 void Settings::setShowSystemTray(bool newValue)
1043 {
1044 QMutexLocker locker{&bigLock};
1045
1046 if (newValue != showSystemTray) {
1047 showSystemTray = newValue;
1048 emit showSystemTrayChanged(newValue);
1049 }
1050 }
1051
setUseEmoticons(bool newValue)1052 void Settings::setUseEmoticons(bool newValue)
1053 {
1054 QMutexLocker locker{&bigLock};
1055
1056 if (newValue != useEmoticons) {
1057 useEmoticons = newValue;
1058 emit useEmoticonsChanged(useEmoticons);
1059 }
1060 }
1061
getUseEmoticons() const1062 bool Settings::getUseEmoticons() const
1063 {
1064 QMutexLocker locker{&bigLock};
1065 return useEmoticons;
1066 }
1067
setAutoSaveEnabled(bool newValue)1068 void Settings::setAutoSaveEnabled(bool newValue)
1069 {
1070 QMutexLocker locker{&bigLock};
1071
1072 if (newValue != autoSaveEnabled) {
1073 autoSaveEnabled = newValue;
1074 emit autoSaveEnabledChanged(autoSaveEnabled);
1075 }
1076 }
1077
getAutoSaveEnabled() const1078 bool Settings::getAutoSaveEnabled() const
1079 {
1080 QMutexLocker locker{&bigLock};
1081 return autoSaveEnabled;
1082 }
1083
setAutostartInTray(bool newValue)1084 void Settings::setAutostartInTray(bool newValue)
1085 {
1086 QMutexLocker locker{&bigLock};
1087
1088 if (newValue != autostartInTray) {
1089 autostartInTray = newValue;
1090 emit autostartInTrayChanged(autostartInTray);
1091 }
1092 }
1093
getCloseToTray() const1094 bool Settings::getCloseToTray() const
1095 {
1096 QMutexLocker locker{&bigLock};
1097 return closeToTray;
1098 }
1099
setCloseToTray(bool newValue)1100 void Settings::setCloseToTray(bool newValue)
1101 {
1102 QMutexLocker locker{&bigLock};
1103
1104 if (newValue != closeToTray) {
1105 closeToTray = newValue;
1106 emit closeToTrayChanged(newValue);
1107 }
1108 }
1109
getMinimizeToTray() const1110 bool Settings::getMinimizeToTray() const
1111 {
1112 QMutexLocker locker{&bigLock};
1113 return minimizeToTray;
1114 }
1115
setMinimizeToTray(bool newValue)1116 void Settings::setMinimizeToTray(bool newValue)
1117 {
1118 QMutexLocker locker{&bigLock};
1119
1120 if (newValue != minimizeToTray) {
1121 minimizeToTray = newValue;
1122 emit minimizeToTrayChanged(minimizeToTray);
1123 }
1124 }
1125
getLightTrayIcon() const1126 bool Settings::getLightTrayIcon() const
1127 {
1128 QMutexLocker locker{&bigLock};
1129 return lightTrayIcon;
1130 }
1131
setLightTrayIcon(bool newValue)1132 void Settings::setLightTrayIcon(bool newValue)
1133 {
1134 QMutexLocker locker{&bigLock};
1135
1136 if (newValue != lightTrayIcon) {
1137 lightTrayIcon = newValue;
1138 emit lightTrayIconChanged(lightTrayIcon);
1139 }
1140 }
1141
getStatusChangeNotificationEnabled() const1142 bool Settings::getStatusChangeNotificationEnabled() const
1143 {
1144 QMutexLocker locker{&bigLock};
1145 return statusChangeNotificationEnabled;
1146 }
1147
setStatusChangeNotificationEnabled(bool newValue)1148 void Settings::setStatusChangeNotificationEnabled(bool newValue)
1149 {
1150 QMutexLocker locker{&bigLock};
1151
1152 if (newValue != statusChangeNotificationEnabled) {
1153 statusChangeNotificationEnabled = newValue;
1154 emit statusChangeNotificationEnabledChanged(statusChangeNotificationEnabled);
1155 }
1156 }
1157
getSpellCheckingEnabled() const1158 bool Settings::getSpellCheckingEnabled() const
1159 {
1160 const QMutexLocker locker{&bigLock};
1161 return spellCheckingEnabled;
1162 }
1163
setSpellCheckingEnabled(bool newValue)1164 void Settings::setSpellCheckingEnabled(bool newValue)
1165 {
1166 QMutexLocker locker{&bigLock};
1167
1168 if (newValue != spellCheckingEnabled) {
1169 spellCheckingEnabled = newValue;
1170 emit statusChangeNotificationEnabledChanged(statusChangeNotificationEnabled);
1171 }
1172 }
1173
getNotifySound() const1174 bool Settings::getNotifySound() const
1175 {
1176 QMutexLocker locker{&bigLock};
1177 return notifySound;
1178 }
1179
setNotifySound(bool newValue)1180 void Settings::setNotifySound(bool newValue)
1181 {
1182 QMutexLocker locker{&bigLock};
1183
1184 if (newValue != notifySound) {
1185 notifySound = newValue;
1186 emit notifySoundChanged(notifySound);
1187 }
1188 }
1189
getNotifyHide() const1190 bool Settings::getNotifyHide() const
1191 {
1192 QMutexLocker locker{&bigLock};
1193 return notifyHide;
1194 }
1195
setNotifyHide(bool newValue)1196 void Settings::setNotifyHide(bool newValue)
1197 {
1198 QMutexLocker locker{&bigLock};
1199
1200 if (newValue != notifyHide) {
1201 notifyHide = newValue;
1202 emit notifyHideChanged(notifyHide);
1203 }
1204 }
1205
getBusySound() const1206 bool Settings::getBusySound() const
1207 {
1208 QMutexLocker locker{&bigLock};
1209 return busySound;
1210 }
1211
setBusySound(bool newValue)1212 void Settings::setBusySound(bool newValue)
1213 {
1214 QMutexLocker locker{&bigLock};
1215
1216 if (newValue != busySound) {
1217 busySound = newValue;
1218 emit busySoundChanged(busySound);
1219 }
1220 }
1221
getGroupAlwaysNotify() const1222 bool Settings::getGroupAlwaysNotify() const
1223 {
1224 QMutexLocker locker{&bigLock};
1225 return groupAlwaysNotify;
1226 }
1227
setGroupAlwaysNotify(bool newValue)1228 void Settings::setGroupAlwaysNotify(bool newValue)
1229 {
1230 QMutexLocker locker{&bigLock};
1231
1232 if (newValue != groupAlwaysNotify) {
1233 groupAlwaysNotify = newValue;
1234 emit groupAlwaysNotifyChanged(groupAlwaysNotify);
1235 }
1236 }
1237
getTranslation() const1238 QString Settings::getTranslation() const
1239 {
1240 QMutexLocker locker{&bigLock};
1241 return translation;
1242 }
1243
setTranslation(const QString & newValue)1244 void Settings::setTranslation(const QString& newValue)
1245 {
1246 QMutexLocker locker{&bigLock};
1247
1248 if (newValue != translation) {
1249 translation = newValue;
1250 emit translationChanged(translation);
1251 }
1252 }
1253
getForceTCP() const1254 bool Settings::getForceTCP() const
1255 {
1256 QMutexLocker locker{&bigLock};
1257 return forceTCP;
1258 }
1259
setForceTCP(bool enabled)1260 void Settings::setForceTCP(bool enabled)
1261 {
1262 QMutexLocker locker{&bigLock};
1263
1264 if (enabled != forceTCP) {
1265 forceTCP = enabled;
1266 emit forceTCPChanged(forceTCP);
1267 }
1268 }
1269
getEnableLanDiscovery() const1270 bool Settings::getEnableLanDiscovery() const
1271 {
1272 QMutexLocker locker{&bigLock};
1273 return enableLanDiscovery;
1274 }
1275
setEnableLanDiscovery(bool enabled)1276 void Settings::setEnableLanDiscovery(bool enabled)
1277 {
1278 QMutexLocker locker{&bigLock};
1279
1280 if (enabled != enableLanDiscovery) {
1281 enableLanDiscovery = enabled;
1282 emit enableLanDiscoveryChanged(enableLanDiscovery);
1283 }
1284 }
1285
getProxy() const1286 QNetworkProxy Settings::getProxy() const
1287 {
1288 QMutexLocker locker{&bigLock};
1289
1290 QNetworkProxy proxy;
1291 switch (Settings::getProxyType()) {
1292 case ProxyType::ptNone:
1293 proxy.setType(QNetworkProxy::NoProxy);
1294 break;
1295 case ProxyType::ptSOCKS5:
1296 proxy.setType(QNetworkProxy::Socks5Proxy);
1297 break;
1298 case ProxyType::ptHTTP:
1299 proxy.setType(QNetworkProxy::HttpProxy);
1300 break;
1301 default:
1302 proxy.setType(QNetworkProxy::NoProxy);
1303 qWarning() << "Invalid Proxy type, setting to NoProxy";
1304 break;
1305 }
1306
1307 proxy.setHostName(Settings::getProxyAddr());
1308 proxy.setPort(Settings::getProxyPort());
1309 return proxy;
1310 }
1311
getProxyType() const1312 Settings::ProxyType Settings::getProxyType() const
1313 {
1314 QMutexLocker locker{&bigLock};
1315 return proxyType;
1316 }
1317
setProxyType(ProxyType newValue)1318 void Settings::setProxyType(ProxyType newValue)
1319 {
1320 QMutexLocker locker{&bigLock};
1321
1322 if (newValue != proxyType) {
1323 proxyType = newValue;
1324 emit proxyTypeChanged(proxyType);
1325 }
1326 }
1327
getProxyAddr() const1328 QString Settings::getProxyAddr() const
1329 {
1330 QMutexLocker locker{&bigLock};
1331 return proxyAddr;
1332 }
1333
setProxyAddr(const QString & address)1334 void Settings::setProxyAddr(const QString& address)
1335 {
1336 QMutexLocker locker{&bigLock};
1337
1338 if (address != proxyAddr) {
1339 proxyAddr = address;
1340 emit proxyAddressChanged(proxyAddr);
1341 }
1342 }
1343
getProxyPort() const1344 quint16 Settings::getProxyPort() const
1345 {
1346 QMutexLocker locker{&bigLock};
1347 return proxyPort;
1348 }
1349
setProxyPort(quint16 port)1350 void Settings::setProxyPort(quint16 port)
1351 {
1352 QMutexLocker locker{&bigLock};
1353
1354 if (port != proxyPort) {
1355 proxyPort = port;
1356 emit proxyPortChanged(proxyPort);
1357 }
1358 }
1359
getCurrentProfile() const1360 QString Settings::getCurrentProfile() const
1361 {
1362 QMutexLocker locker{&bigLock};
1363 return currentProfile;
1364 }
1365
getCurrentProfileId() const1366 uint32_t Settings::getCurrentProfileId() const
1367 {
1368 QMutexLocker locker{&bigLock};
1369 return currentProfileId;
1370 }
1371
setCurrentProfile(const QString & profile)1372 void Settings::setCurrentProfile(const QString& profile)
1373 {
1374 QMutexLocker locker{&bigLock};
1375
1376 if (profile != currentProfile) {
1377 currentProfile = profile;
1378 currentProfileId = makeProfileId(currentProfile);
1379
1380 emit currentProfileIdChanged(currentProfileId);
1381 }
1382 }
1383
getEnableLogging() const1384 bool Settings::getEnableLogging() const
1385 {
1386 QMutexLocker locker{&bigLock};
1387 return enableLogging;
1388 }
1389
setEnableLogging(bool newValue)1390 void Settings::setEnableLogging(bool newValue)
1391 {
1392 QMutexLocker locker{&bigLock};
1393
1394 if (newValue != enableLogging) {
1395 enableLogging = newValue;
1396 emit enableLoggingChanged(enableLogging);
1397 }
1398 }
1399
getAutoAwayTime() const1400 int Settings::getAutoAwayTime() const
1401 {
1402 QMutexLocker locker{&bigLock};
1403 return autoAwayTime;
1404 }
1405
1406 /**
1407 * @brief Sets how long the user may stay idle, before online status is set to "away".
1408 * @param[in] newValue the user idle duration in minutes
1409 * @note Values < 0 default to 10 minutes.
1410 */
setAutoAwayTime(int newValue)1411 void Settings::setAutoAwayTime(int newValue)
1412 {
1413 QMutexLocker locker{&bigLock};
1414
1415 if (newValue < 0)
1416 newValue = 10;
1417
1418 if (newValue != autoAwayTime) {
1419 autoAwayTime = newValue;
1420 emit autoAwayTimeChanged(autoAwayTime);
1421 }
1422 }
1423
getAutoAcceptDir(const ToxPk & id) const1424 QString Settings::getAutoAcceptDir(const ToxPk& id) const
1425 {
1426 QMutexLocker locker{&bigLock};
1427
1428 auto it = friendLst.find(id.getByteArray());
1429 if (it != friendLst.end())
1430 return it->autoAcceptDir;
1431
1432 return QString();
1433 }
1434
setAutoAcceptDir(const ToxPk & id,const QString & dir)1435 void Settings::setAutoAcceptDir(const ToxPk& id, const QString& dir)
1436 {
1437 QMutexLocker locker{&bigLock};
1438
1439 auto& frnd = getOrInsertFriendPropRef(id);
1440
1441 if (frnd.autoAcceptDir != dir) {
1442 frnd.autoAcceptDir = dir;
1443 emit autoAcceptDirChanged(id, dir);
1444 }
1445 }
1446
getAutoAcceptCall(const ToxPk & id) const1447 Settings::AutoAcceptCallFlags Settings::getAutoAcceptCall(const ToxPk& id) const
1448 {
1449 QMutexLocker locker{&bigLock};
1450
1451 auto it = friendLst.find(id.getByteArray());
1452 if (it != friendLst.end())
1453 return it->autoAcceptCall;
1454
1455 return Settings::AutoAcceptCallFlags();
1456 }
1457
setAutoAcceptCall(const ToxPk & id,AutoAcceptCallFlags accept)1458 void Settings::setAutoAcceptCall(const ToxPk& id, AutoAcceptCallFlags accept)
1459 {
1460 QMutexLocker locker{&bigLock};
1461
1462 auto& frnd = getOrInsertFriendPropRef(id);
1463
1464 if (frnd.autoAcceptCall != accept) {
1465 frnd.autoAcceptCall = accept;
1466 emit autoAcceptCallChanged(id, accept);
1467 }
1468 }
1469
getAutoGroupInvite(const ToxPk & id) const1470 bool Settings::getAutoGroupInvite(const ToxPk& id) const
1471 {
1472 QMutexLocker locker{&bigLock};
1473
1474 auto it = friendLst.find(id.getByteArray());
1475 if (it != friendLst.end()) {
1476 return it->autoGroupInvite;
1477 }
1478
1479 return false;
1480 }
1481
setAutoGroupInvite(const ToxPk & id,bool accept)1482 void Settings::setAutoGroupInvite(const ToxPk& id, bool accept)
1483 {
1484 QMutexLocker locker{&bigLock};
1485
1486 auto& frnd = getOrInsertFriendPropRef(id);
1487
1488 if (frnd.autoGroupInvite != accept) {
1489 frnd.autoGroupInvite = accept;
1490 emit autoGroupInviteChanged(id, accept);
1491 }
1492 }
1493
getContactNote(const ToxPk & id) const1494 QString Settings::getContactNote(const ToxPk& id) const
1495 {
1496 QMutexLocker locker{&bigLock};
1497
1498 auto it = friendLst.find(id.getByteArray());
1499 if (it != friendLst.end())
1500 return it->note;
1501
1502 return QString();
1503 }
1504
setContactNote(const ToxPk & id,const QString & note)1505 void Settings::setContactNote(const ToxPk& id, const QString& note)
1506 {
1507 QMutexLocker locker{&bigLock};
1508
1509 auto& frnd = getOrInsertFriendPropRef(id);
1510
1511 if (frnd.note != note) {
1512 frnd.note = note;
1513 emit contactNoteChanged(id, note);
1514 }
1515 }
1516
getGlobalAutoAcceptDir() const1517 QString Settings::getGlobalAutoAcceptDir() const
1518 {
1519 QMutexLocker locker{&bigLock};
1520 return globalAutoAcceptDir;
1521 }
1522
setGlobalAutoAcceptDir(const QString & newValue)1523 void Settings::setGlobalAutoAcceptDir(const QString& newValue)
1524 {
1525 QMutexLocker locker{&bigLock};
1526
1527 if (newValue != globalAutoAcceptDir) {
1528 globalAutoAcceptDir = newValue;
1529 emit globalAutoAcceptDirChanged(globalAutoAcceptDir);
1530 }
1531 }
1532
getMaxAutoAcceptSize() const1533 size_t Settings::getMaxAutoAcceptSize() const
1534 {
1535 QMutexLocker locker{&bigLock};
1536 return autoAcceptMaxSize;
1537 }
1538
setMaxAutoAcceptSize(size_t size)1539 void Settings::setMaxAutoAcceptSize(size_t size)
1540 {
1541 QMutexLocker locker{&bigLock};
1542
1543 if (size != autoAcceptMaxSize) {
1544 autoAcceptMaxSize = size;
1545 emit autoAcceptMaxSizeChanged(autoAcceptMaxSize);
1546 }
1547 }
1548
getChatMessageFont() const1549 const QFont& Settings::getChatMessageFont() const
1550 {
1551 QMutexLocker locker(&bigLock);
1552 return chatMessageFont;
1553 }
1554
setChatMessageFont(const QFont & font)1555 void Settings::setChatMessageFont(const QFont& font)
1556 {
1557 QMutexLocker locker(&bigLock);
1558
1559 if (font != chatMessageFont) {
1560 chatMessageFont = font;
1561 emit chatMessageFontChanged(chatMessageFont);
1562 }
1563 }
1564
setWidgetData(const QString & uniqueName,const QByteArray & data)1565 void Settings::setWidgetData(const QString& uniqueName, const QByteArray& data)
1566 {
1567 QMutexLocker locker{&bigLock};
1568
1569 if (!widgetSettings.contains(uniqueName) || widgetSettings[uniqueName] != data) {
1570 widgetSettings[uniqueName] = data;
1571 emit widgetDataChanged(uniqueName);
1572 }
1573 }
1574
getWidgetData(const QString & uniqueName) const1575 QByteArray Settings::getWidgetData(const QString& uniqueName) const
1576 {
1577 QMutexLocker locker{&bigLock};
1578 return widgetSettings.value(uniqueName);
1579 }
1580
getSmileyPack() const1581 QString Settings::getSmileyPack() const
1582 {
1583 QMutexLocker locker{&bigLock};
1584 return smileyPack;
1585 }
1586
setSmileyPack(const QString & value)1587 void Settings::setSmileyPack(const QString& value)
1588 {
1589 QMutexLocker locker{&bigLock};
1590
1591 if (value != smileyPack) {
1592 smileyPack = value;
1593 emit smileyPackChanged(smileyPack);
1594 }
1595 }
1596
getEmojiFontPointSize() const1597 int Settings::getEmojiFontPointSize() const
1598 {
1599 QMutexLocker locker{&bigLock};
1600 return emojiFontPointSize;
1601 }
1602
setEmojiFontPointSize(int value)1603 void Settings::setEmojiFontPointSize(int value)
1604 {
1605 QMutexLocker locker{&bigLock};
1606
1607 if (value != emojiFontPointSize) {
1608 emojiFontPointSize = value;
1609 emit emojiFontPointSizeChanged(emojiFontPointSize);
1610 }
1611 }
1612
getTimestampFormat() const1613 const QString& Settings::getTimestampFormat() const
1614 {
1615 QMutexLocker locker{&bigLock};
1616 return timestampFormat;
1617 }
1618
setTimestampFormat(const QString & format)1619 void Settings::setTimestampFormat(const QString& format)
1620 {
1621 QMutexLocker locker{&bigLock};
1622
1623 if (format != timestampFormat) {
1624 timestampFormat = format;
1625 emit timestampFormatChanged(timestampFormat);
1626 }
1627 }
1628
getDateFormat() const1629 const QString& Settings::getDateFormat() const
1630 {
1631 QMutexLocker locker{&bigLock};
1632 return dateFormat;
1633 }
1634
setDateFormat(const QString & format)1635 void Settings::setDateFormat(const QString& format)
1636 {
1637 QMutexLocker locker{&bigLock};
1638
1639 if (format != dateFormat) {
1640 dateFormat = format;
1641 emit dateFormatChanged(dateFormat);
1642 }
1643 }
1644
getStylePreference() const1645 Settings::StyleType Settings::getStylePreference() const
1646 {
1647 QMutexLocker locker{&bigLock};
1648 return stylePreference;
1649 }
1650
setStylePreference(StyleType newValue)1651 void Settings::setStylePreference(StyleType newValue)
1652 {
1653 QMutexLocker locker{&bigLock};
1654
1655 if (newValue != stylePreference) {
1656 stylePreference = newValue;
1657 emit stylePreferenceChanged(stylePreference);
1658 }
1659 }
1660
getWindowGeometry() const1661 QByteArray Settings::getWindowGeometry() const
1662 {
1663 QMutexLocker locker{&bigLock};
1664 return windowGeometry;
1665 }
1666
setWindowGeometry(const QByteArray & value)1667 void Settings::setWindowGeometry(const QByteArray& value)
1668 {
1669 QMutexLocker locker{&bigLock};
1670
1671 if (value != windowGeometry) {
1672 windowGeometry = value;
1673 emit windowGeometryChanged(windowGeometry);
1674 }
1675 }
1676
getWindowState() const1677 QByteArray Settings::getWindowState() const
1678 {
1679 QMutexLocker locker{&bigLock};
1680 return windowState;
1681 }
1682
setWindowState(const QByteArray & value)1683 void Settings::setWindowState(const QByteArray& value)
1684 {
1685 QMutexLocker locker{&bigLock};
1686
1687 if (value != windowState) {
1688 windowState = value;
1689 emit windowStateChanged(windowState);
1690 }
1691 }
1692
getCheckUpdates() const1693 bool Settings::getCheckUpdates() const
1694 {
1695 QMutexLocker locker{&bigLock};
1696 return checkUpdates;
1697 }
1698
setCheckUpdates(bool newValue)1699 void Settings::setCheckUpdates(bool newValue)
1700 {
1701 QMutexLocker locker{&bigLock};
1702
1703 if (newValue != checkUpdates) {
1704 checkUpdates = newValue;
1705 emit checkUpdatesChanged(checkUpdates);
1706 }
1707 }
1708
getNotify() const1709 bool Settings::getNotify() const
1710 {
1711 QMutexLocker locker{&bigLock};
1712 return notify;
1713 }
1714
setNotify(bool newValue)1715 void Settings::setNotify(bool newValue)
1716 {
1717 QMutexLocker locker{&bigLock};
1718 if (newValue != notify) {
1719 notify = newValue;
1720 emit notifyChanged(notify);
1721 }
1722 }
1723
getShowWindow() const1724 bool Settings::getShowWindow() const
1725 {
1726 QMutexLocker locker{&bigLock};
1727 return showWindow;
1728 }
1729
setShowWindow(bool newValue)1730 void Settings::setShowWindow(bool newValue)
1731 {
1732 QMutexLocker locker{&bigLock};
1733
1734 if (newValue != showWindow) {
1735 showWindow = newValue;
1736 emit showWindowChanged(showWindow);
1737 }
1738 }
1739
getDesktopNotify() const1740 bool Settings::getDesktopNotify() const
1741 {
1742 QMutexLocker locker{&bigLock};
1743 return desktopNotify;
1744 }
1745
setDesktopNotify(bool enabled)1746 void Settings::setDesktopNotify(bool enabled)
1747 {
1748 QMutexLocker locker{&bigLock};
1749
1750 if (enabled != desktopNotify) {
1751 desktopNotify = enabled;
1752 emit desktopNotifyChanged(desktopNotify);
1753 }
1754 }
1755
getSplitterState() const1756 QByteArray Settings::getSplitterState() const
1757 {
1758 QMutexLocker locker{&bigLock};
1759 return splitterState;
1760 }
1761
setSplitterState(const QByteArray & value)1762 void Settings::setSplitterState(const QByteArray& value)
1763 {
1764 QMutexLocker locker{&bigLock};
1765
1766 if (value != splitterState) {
1767 splitterState = value;
1768 emit splitterStateChanged(splitterState);
1769 }
1770 }
1771
getDialogGeometry() const1772 QByteArray Settings::getDialogGeometry() const
1773 {
1774 QMutexLocker locker{&bigLock};
1775 return dialogGeometry;
1776 }
1777
setDialogGeometry(const QByteArray & value)1778 void Settings::setDialogGeometry(const QByteArray& value)
1779 {
1780 QMutexLocker locker{&bigLock};
1781
1782 if (value != dialogGeometry) {
1783 dialogGeometry = value;
1784 emit dialogGeometryChanged(dialogGeometry);
1785 }
1786 }
1787
getDialogSplitterState() const1788 QByteArray Settings::getDialogSplitterState() const
1789 {
1790 QMutexLocker locker{&bigLock};
1791 return dialogSplitterState;
1792 }
1793
setDialogSplitterState(const QByteArray & value)1794 void Settings::setDialogSplitterState(const QByteArray& value)
1795 {
1796 QMutexLocker locker{&bigLock};
1797
1798 if (value != dialogSplitterState) {
1799 dialogSplitterState = value;
1800 emit dialogSplitterStateChanged(dialogSplitterState);
1801 }
1802 }
1803
getDialogSettingsGeometry() const1804 QByteArray Settings::getDialogSettingsGeometry() const
1805 {
1806 QMutexLocker locker{&bigLock};
1807 return dialogSettingsGeometry;
1808 }
1809
setDialogSettingsGeometry(const QByteArray & value)1810 void Settings::setDialogSettingsGeometry(const QByteArray& value)
1811 {
1812 QMutexLocker locker{&bigLock};
1813
1814 if (value != dialogSettingsGeometry) {
1815 dialogSettingsGeometry = value;
1816 emit dialogSettingsGeometryChanged(dialogSettingsGeometry);
1817 }
1818 }
1819
getMinimizeOnClose() const1820 bool Settings::getMinimizeOnClose() const
1821 {
1822 QMutexLocker locker{&bigLock};
1823 return minimizeOnClose;
1824 }
1825
setMinimizeOnClose(bool newValue)1826 void Settings::setMinimizeOnClose(bool newValue)
1827 {
1828 QMutexLocker locker{&bigLock};
1829
1830 if (newValue != minimizeOnClose) {
1831 minimizeOnClose = newValue;
1832 emit minimizeOnCloseChanged(minimizeOnClose);
1833 }
1834 }
1835
getTypingNotification() const1836 bool Settings::getTypingNotification() const
1837 {
1838 QMutexLocker locker{&bigLock};
1839 return typingNotification;
1840 }
1841
setTypingNotification(bool enabled)1842 void Settings::setTypingNotification(bool enabled)
1843 {
1844 QMutexLocker locker{&bigLock};
1845
1846 if (enabled != typingNotification) {
1847 typingNotification = enabled;
1848 emit typingNotificationChanged(typingNotification);
1849 }
1850 }
1851
getBlackList() const1852 QStringList Settings::getBlackList() const
1853 {
1854 QMutexLocker locker{&bigLock};
1855 return blackList;
1856 }
1857
setBlackList(const QStringList & blist)1858 void Settings::setBlackList(const QStringList& blist)
1859 {
1860 QMutexLocker locker{&bigLock};
1861
1862 if (blist != blackList) {
1863 blackList = blist;
1864 emit blackListChanged(blackList);
1865 }
1866 }
1867
getInDev() const1868 QString Settings::getInDev() const
1869 {
1870 QMutexLocker locker{&bigLock};
1871 return inDev;
1872 }
1873
setInDev(const QString & deviceSpecifier)1874 void Settings::setInDev(const QString& deviceSpecifier)
1875 {
1876 QMutexLocker locker{&bigLock};
1877
1878 if (deviceSpecifier != inDev) {
1879 inDev = deviceSpecifier;
1880 emit inDevChanged(inDev);
1881 }
1882 }
1883
getAudioInDevEnabled() const1884 bool Settings::getAudioInDevEnabled() const
1885 {
1886 QMutexLocker locker(&bigLock);
1887 return audioInDevEnabled;
1888 }
1889
setAudioInDevEnabled(bool enabled)1890 void Settings::setAudioInDevEnabled(bool enabled)
1891 {
1892 QMutexLocker locker(&bigLock);
1893
1894 if (enabled != audioInDevEnabled) {
1895 audioInDevEnabled = enabled;
1896 emit audioInDevEnabledChanged(enabled);
1897 }
1898 }
1899
getAudioInGainDecibel() const1900 qreal Settings::getAudioInGainDecibel() const
1901 {
1902 QMutexLocker locker{&bigLock};
1903 return audioInGainDecibel;
1904 }
1905
setAudioInGainDecibel(qreal dB)1906 void Settings::setAudioInGainDecibel(qreal dB)
1907 {
1908 QMutexLocker locker{&bigLock};
1909
1910 if (dB < audioInGainDecibel || dB > audioInGainDecibel) {
1911 audioInGainDecibel = dB;
1912 emit audioInGainDecibelChanged(audioInGainDecibel);
1913 }
1914 }
1915
getAudioThreshold() const1916 qreal Settings::getAudioThreshold() const
1917 {
1918 QMutexLocker locker{&bigLock};
1919 return audioThreshold;
1920 }
1921
setAudioThreshold(qreal percent)1922 void Settings::setAudioThreshold(qreal percent)
1923 {
1924 QMutexLocker locker{&bigLock};
1925
1926 if (percent < audioThreshold || percent > audioThreshold) {
1927 audioThreshold = percent;
1928 emit audioThresholdChanged(audioThreshold);
1929 }
1930 }
1931
getVideoDev() const1932 QString Settings::getVideoDev() const
1933 {
1934 QMutexLocker locker{&bigLock};
1935 return videoDev;
1936 }
1937
setVideoDev(const QString & deviceSpecifier)1938 void Settings::setVideoDev(const QString& deviceSpecifier)
1939 {
1940 QMutexLocker locker{&bigLock};
1941
1942 if (deviceSpecifier != videoDev) {
1943 videoDev = deviceSpecifier;
1944 emit videoDevChanged(videoDev);
1945 }
1946 }
1947
getOutDev() const1948 QString Settings::getOutDev() const
1949 {
1950 QMutexLocker locker{&bigLock};
1951 return outDev;
1952 }
1953
setOutDev(const QString & deviceSpecifier)1954 void Settings::setOutDev(const QString& deviceSpecifier)
1955 {
1956 QMutexLocker locker{&bigLock};
1957
1958 if (deviceSpecifier != outDev) {
1959 outDev = deviceSpecifier;
1960 emit outDevChanged(outDev);
1961 }
1962 }
1963
getAudioOutDevEnabled() const1964 bool Settings::getAudioOutDevEnabled() const
1965 {
1966 QMutexLocker locker(&bigLock);
1967 return audioOutDevEnabled;
1968 }
1969
setAudioOutDevEnabled(bool enabled)1970 void Settings::setAudioOutDevEnabled(bool enabled)
1971 {
1972 QMutexLocker locker(&bigLock);
1973
1974 if (enabled != audioOutDevEnabled) {
1975 audioOutDevEnabled = enabled;
1976 emit audioOutDevEnabledChanged(audioOutDevEnabled);
1977 }
1978 }
1979
getOutVolume() const1980 int Settings::getOutVolume() const
1981 {
1982 QMutexLocker locker{&bigLock};
1983 return outVolume;
1984 }
1985
setOutVolume(int volume)1986 void Settings::setOutVolume(int volume)
1987 {
1988 QMutexLocker locker{&bigLock};
1989
1990 if (volume != outVolume) {
1991 outVolume = volume;
1992 emit outVolumeChanged(outVolume);
1993 }
1994 }
1995
getAudioBitrate() const1996 int Settings::getAudioBitrate() const
1997 {
1998 const QMutexLocker locker{&bigLock};
1999 return audioBitrate;
2000 }
2001
setAudioBitrate(int bitrate)2002 void Settings::setAudioBitrate(int bitrate)
2003 {
2004 const QMutexLocker locker{&bigLock};
2005
2006 if (bitrate != audioBitrate) {
2007 audioBitrate = bitrate;
2008 emit audioBitrateChanged(audioBitrate);
2009 }
2010 }
2011
getScreenRegion() const2012 QRect Settings::getScreenRegion() const
2013 {
2014 QMutexLocker locker(&bigLock);
2015 return screenRegion;
2016 }
2017
setScreenRegion(const QRect & value)2018 void Settings::setScreenRegion(const QRect& value)
2019 {
2020 QMutexLocker locker{&bigLock};
2021
2022 if (value != screenRegion) {
2023 screenRegion = value;
2024 emit screenRegionChanged(screenRegion);
2025 }
2026 }
2027
getScreenGrabbed() const2028 bool Settings::getScreenGrabbed() const
2029 {
2030 QMutexLocker locker(&bigLock);
2031 return screenGrabbed;
2032 }
2033
setScreenGrabbed(bool value)2034 void Settings::setScreenGrabbed(bool value)
2035 {
2036 QMutexLocker locker{&bigLock};
2037
2038 if (value != screenGrabbed) {
2039 screenGrabbed = value;
2040 emit screenGrabbedChanged(screenGrabbed);
2041 }
2042 }
2043
getCamVideoRes() const2044 QRect Settings::getCamVideoRes() const
2045 {
2046 QMutexLocker locker{&bigLock};
2047 return camVideoRes;
2048 }
2049
setCamVideoRes(QRect newValue)2050 void Settings::setCamVideoRes(QRect newValue)
2051 {
2052 QMutexLocker locker{&bigLock};
2053
2054 if (newValue != camVideoRes) {
2055 camVideoRes = newValue;
2056 emit camVideoResChanged(camVideoRes);
2057 }
2058 }
2059
getCamVideoFPS() const2060 float Settings::getCamVideoFPS() const
2061 {
2062 QMutexLocker locker{&bigLock};
2063 return camVideoFPS;
2064 }
2065
setCamVideoFPS(float newValue)2066 void Settings::setCamVideoFPS(float newValue)
2067 {
2068 QMutexLocker locker{&bigLock};
2069
2070 if (newValue != camVideoFPS) {
2071 camVideoFPS = newValue;
2072 emit camVideoFPSChanged(camVideoFPS);
2073 }
2074 }
2075
getFriendAddress(const QString & publicKey) const2076 QString Settings::getFriendAddress(const QString& publicKey) const
2077 {
2078 QMutexLocker locker{&bigLock};
2079 // TODO: using ToxId here is a hack
2080 QByteArray key = ToxId(publicKey).getPublicKey().getByteArray();
2081 auto it = friendLst.find(key);
2082 if (it != friendLst.end())
2083 return it->addr;
2084
2085 return QString();
2086 }
2087
updateFriendAddress(const QString & newAddr)2088 void Settings::updateFriendAddress(const QString& newAddr)
2089 {
2090 QMutexLocker locker{&bigLock};
2091 // TODO: using ToxId here is a hack
2092 auto key = ToxId(newAddr).getPublicKey();
2093 auto& frnd = getOrInsertFriendPropRef(key);
2094 frnd.addr = newAddr;
2095 }
2096
getFriendAlias(const ToxPk & id) const2097 QString Settings::getFriendAlias(const ToxPk& id) const
2098 {
2099 QMutexLocker locker{&bigLock};
2100 auto it = friendLst.find(id.getByteArray());
2101 if (it != friendLst.end())
2102 return it->alias;
2103
2104 return QString();
2105 }
2106
setFriendAlias(const ToxPk & id,const QString & alias)2107 void Settings::setFriendAlias(const ToxPk& id, const QString& alias)
2108 {
2109 QMutexLocker locker{&bigLock};
2110 auto& frnd = getOrInsertFriendPropRef(id);
2111 frnd.alias = alias;
2112 }
2113
getFriendCircleID(const ToxPk & id) const2114 int Settings::getFriendCircleID(const ToxPk& id) const
2115 {
2116 QMutexLocker locker{&bigLock};
2117 auto it = friendLst.find(id.getByteArray());
2118 if (it != friendLst.end())
2119 return it->circleID;
2120
2121 return -1;
2122 }
2123
setFriendCircleID(const ToxPk & id,int circleID)2124 void Settings::setFriendCircleID(const ToxPk& id, int circleID)
2125 {
2126 QMutexLocker locker{&bigLock};
2127 auto& frnd = getOrInsertFriendPropRef(id);
2128 frnd.circleID = circleID;
2129 }
2130
getFriendActivity(const ToxPk & id) const2131 QDateTime Settings::getFriendActivity(const ToxPk& id) const
2132 {
2133 QMutexLocker locker{&bigLock};
2134 auto it = friendLst.find(id.getByteArray());
2135 if (it != friendLst.end())
2136 return it->activity;
2137
2138 return QDateTime();
2139 }
2140
setFriendActivity(const ToxPk & id,const QDateTime & activity)2141 void Settings::setFriendActivity(const ToxPk& id, const QDateTime& activity)
2142 {
2143 QMutexLocker locker{&bigLock};
2144 auto& frnd = getOrInsertFriendPropRef(id);
2145 frnd.activity = activity;
2146 }
2147
saveFriendSettings(const ToxPk & id)2148 void Settings::saveFriendSettings(const ToxPk& id)
2149 {
2150 Q_UNUSED(id);
2151 savePersonal();
2152 }
2153
removeFriendSettings(const ToxPk & id)2154 void Settings::removeFriendSettings(const ToxPk& id)
2155 {
2156 QMutexLocker locker{&bigLock};
2157 friendLst.remove(id.getByteArray());
2158 }
2159
getCompactLayout() const2160 bool Settings::getCompactLayout() const
2161 {
2162 QMutexLocker locker{&bigLock};
2163 return compactLayout;
2164 }
2165
setCompactLayout(bool value)2166 void Settings::setCompactLayout(bool value)
2167 {
2168 QMutexLocker locker{&bigLock};
2169
2170 if (value != compactLayout) {
2171 compactLayout = value;
2172 emit compactLayoutChanged(value);
2173 }
2174 }
2175
getFriendSortingMode() const2176 Settings::FriendListSortingMode Settings::getFriendSortingMode() const
2177 {
2178 QMutexLocker locker{&bigLock};
2179 return sortingMode;
2180 }
2181
setFriendSortingMode(FriendListSortingMode mode)2182 void Settings::setFriendSortingMode(FriendListSortingMode mode)
2183 {
2184 QMutexLocker locker{&bigLock};
2185
2186 if (mode != sortingMode) {
2187 sortingMode = mode;
2188 emit sortingModeChanged(sortingMode);
2189 }
2190 }
2191
getSeparateWindow() const2192 bool Settings::getSeparateWindow() const
2193 {
2194 QMutexLocker locker{&bigLock};
2195 return separateWindow;
2196 }
2197
setSeparateWindow(bool value)2198 void Settings::setSeparateWindow(bool value)
2199 {
2200 QMutexLocker locker{&bigLock};
2201
2202 if (value != separateWindow) {
2203 separateWindow = value;
2204 emit separateWindowChanged(value);
2205 }
2206 }
2207
getDontGroupWindows() const2208 bool Settings::getDontGroupWindows() const
2209 {
2210 QMutexLocker locker{&bigLock};
2211 return dontGroupWindows;
2212 }
2213
setDontGroupWindows(bool value)2214 void Settings::setDontGroupWindows(bool value)
2215 {
2216 QMutexLocker locker{&bigLock};
2217
2218 if (value != dontGroupWindows) {
2219 dontGroupWindows = value;
2220 emit dontGroupWindowsChanged(dontGroupWindows);
2221 }
2222 }
2223
getGroupchatPosition() const2224 bool Settings::getGroupchatPosition() const
2225 {
2226 QMutexLocker locker{&bigLock};
2227 return groupchatPosition;
2228 }
2229
setGroupchatPosition(bool value)2230 void Settings::setGroupchatPosition(bool value)
2231 {
2232 QMutexLocker locker{&bigLock};
2233
2234 if (value != groupchatPosition) {
2235 groupchatPosition = value;
2236 emit groupchatPositionChanged(value);
2237 }
2238 }
2239
getShowIdenticons() const2240 bool Settings::getShowIdenticons() const
2241 {
2242 const QMutexLocker locker{&bigLock};
2243 return showIdenticons;
2244 }
2245
setShowIdenticons(bool value)2246 void Settings::setShowIdenticons(bool value)
2247 {
2248 const QMutexLocker locker{&bigLock};
2249
2250 if (value != showIdenticons) {
2251 showIdenticons = value;
2252 emit showIdenticonsChanged(value);
2253 }
2254 }
2255
getCircleCount() const2256 int Settings::getCircleCount() const
2257 {
2258 QMutexLocker locker{&bigLock};
2259 return circleLst.size();
2260 }
2261
getCircleName(int id) const2262 QString Settings::getCircleName(int id) const
2263 {
2264 QMutexLocker locker{&bigLock};
2265 return circleLst[id].name;
2266 }
2267
setCircleName(int id,const QString & name)2268 void Settings::setCircleName(int id, const QString& name)
2269 {
2270 QMutexLocker locker{&bigLock};
2271 circleLst[id].name = name;
2272 savePersonal();
2273 }
2274
addCircle(const QString & name)2275 int Settings::addCircle(const QString& name)
2276 {
2277 QMutexLocker locker{&bigLock};
2278
2279 circleProp cp;
2280 cp.expanded = false;
2281
2282 if (name.isEmpty())
2283 cp.name = tr("Circle #%1").arg(circleLst.count() + 1);
2284 else
2285 cp.name = name;
2286
2287 circleLst.append(cp);
2288 savePersonal();
2289 return circleLst.count() - 1;
2290 }
2291
getCircleExpanded(int id) const2292 bool Settings::getCircleExpanded(int id) const
2293 {
2294 QMutexLocker locker{&bigLock};
2295 return circleLst[id].expanded;
2296 }
2297
setCircleExpanded(int id,bool expanded)2298 void Settings::setCircleExpanded(int id, bool expanded)
2299 {
2300 QMutexLocker locker{&bigLock};
2301 circleLst[id].expanded = expanded;
2302 }
2303
addFriendRequest(const QString & friendAddress,const QString & message)2304 bool Settings::addFriendRequest(const QString& friendAddress, const QString& message)
2305 {
2306 QMutexLocker locker{&bigLock};
2307
2308 for (auto queued : friendRequests) {
2309 if (queued.address == friendAddress) {
2310 queued.message = message;
2311 queued.read = false;
2312 return false;
2313 }
2314 }
2315
2316 Request request;
2317 request.address = friendAddress;
2318 request.message = message;
2319 request.read = false;
2320
2321 friendRequests.push_back(request);
2322 return true;
2323 }
2324
getUnreadFriendRequests() const2325 unsigned int Settings::getUnreadFriendRequests() const
2326 {
2327 QMutexLocker locker{&bigLock};
2328 unsigned int unreadFriendRequests = 0;
2329 for (auto request : friendRequests)
2330 if (!request.read)
2331 ++unreadFriendRequests;
2332
2333 return unreadFriendRequests;
2334 }
2335
getFriendRequest(int index) const2336 Settings::Request Settings::getFriendRequest(int index) const
2337 {
2338 QMutexLocker locker{&bigLock};
2339 return friendRequests.at(index);
2340 }
2341
getFriendRequestSize() const2342 int Settings::getFriendRequestSize() const
2343 {
2344 QMutexLocker locker{&bigLock};
2345 return friendRequests.size();
2346 }
2347
clearUnreadFriendRequests()2348 void Settings::clearUnreadFriendRequests()
2349 {
2350 QMutexLocker locker{&bigLock};
2351
2352 for (auto& request : friendRequests)
2353 request.read = true;
2354 }
2355
removeFriendRequest(int index)2356 void Settings::removeFriendRequest(int index)
2357 {
2358 QMutexLocker locker{&bigLock};
2359 friendRequests.removeAt(index);
2360 }
2361
readFriendRequest(int index)2362 void Settings::readFriendRequest(int index)
2363 {
2364 QMutexLocker locker{&bigLock};
2365 friendRequests[index].read = true;
2366 }
2367
removeCircle(int id)2368 int Settings::removeCircle(int id)
2369 {
2370 // Replace index with last one and remove last one instead.
2371 // This gives you contiguous ids all the time.
2372 circleLst[id] = circleLst.last();
2373 circleLst.pop_back();
2374 savePersonal();
2375 return circleLst.count();
2376 }
2377
getThemeColor() const2378 int Settings::getThemeColor() const
2379 {
2380 QMutexLocker locker{&bigLock};
2381 return themeColor;
2382 }
2383
setThemeColor(int value)2384 void Settings::setThemeColor(int value)
2385 {
2386 QMutexLocker locker{&bigLock};
2387
2388 if (value != themeColor) {
2389 themeColor = value;
2390 emit themeColorChanged(themeColor);
2391 }
2392 }
2393
getAutoLogin() const2394 bool Settings::getAutoLogin() const
2395 {
2396 QMutexLocker locker{&bigLock};
2397 return autoLogin;
2398 }
2399
setAutoLogin(bool state)2400 void Settings::setAutoLogin(bool state)
2401 {
2402 QMutexLocker locker{&bigLock};
2403
2404 if (state != autoLogin) {
2405 autoLogin = state;
2406 emit autoLoginChanged(autoLogin);
2407 }
2408 }
2409
setEnableGroupChatsColor(bool state)2410 void Settings::setEnableGroupChatsColor(bool state)
2411 {
2412 QMutexLocker locker{&bigLock};
2413 if (state != nameColors) {
2414 nameColors = state;
2415 emit nameColorsChanged(nameColors);
2416 }
2417 }
2418
getEnableGroupChatsColor() const2419 bool Settings::getEnableGroupChatsColor() const
2420 {
2421 return nameColors;
2422 }
2423
2424 /**
2425 * @brief Write a default personal .ini settings file for a profile.
2426 * @param basename Filename without extension to save settings.
2427 *
2428 * @note If basename is "profile", settings will be saved in profile.ini
2429 */
createPersonal(QString basename)2430 void Settings::createPersonal(QString basename)
2431 {
2432 QMutexLocker locker{&bigLock};
2433
2434 QString path = getSettingsDirPath() + QDir::separator() + basename + ".ini";
2435 qDebug() << "Creating new profile settings in " << path;
2436
2437 QSettings ps(path, QSettings::IniFormat);
2438 ps.setIniCodec("UTF-8");
2439 ps.beginGroup("Friends");
2440 ps.beginWriteArray("Friend", 0);
2441 ps.endArray();
2442 ps.endGroup();
2443
2444 ps.beginGroup("Privacy");
2445 ps.endGroup();
2446 }
2447
2448 /**
2449 * @brief Creates a path to the settings dir, if it doesn't already exist
2450 */
createSettingsDir()2451 void Settings::createSettingsDir()
2452 {
2453 QMutexLocker locker{&bigLock};
2454
2455 QString dir = Settings::getSettingsDirPath();
2456 QDir directory(dir);
2457 if (!directory.exists() && !directory.mkpath(directory.absolutePath()))
2458 qCritical() << "Error while creating directory " << dir;
2459 }
2460
2461 /**
2462 * @brief Waits for all asynchronous operations to complete
2463 */
sync()2464 void Settings::sync()
2465 {
2466 if (QThread::currentThread() != settingsThread) {
2467 QMetaObject::invokeMethod(&getInstance(), "sync", Qt::BlockingQueuedConnection);
2468 return;
2469 }
2470
2471 QMutexLocker locker{&bigLock};
2472 qApp->processEvents();
2473 }
2474
getOrInsertFriendPropRef(const ToxPk & id)2475 Settings::friendProp& Settings::getOrInsertFriendPropRef(const ToxPk& id)
2476 {
2477 // No mutex lock, this is a private fn that should only be called by other
2478 // public functions that already locked the mutex
2479 auto it = friendLst.find(id.getByteArray());
2480 if (it == friendLst.end()) {
2481 it = friendLst.insert(id.getByteArray(), friendProp{id.toString()});
2482 }
2483
2484 return *it;
2485 }
2486
fixInvalidProxyType(ICoreSettings::ProxyType proxyType)2487 ICoreSettings::ProxyType Settings::fixInvalidProxyType(ICoreSettings::ProxyType proxyType)
2488 {
2489 // Repair uninitialized enum that was saved to settings due to bug (https://github.com/qTox/qTox/issues/5311)
2490 switch (proxyType) {
2491 case ICoreSettings::ProxyType::ptNone:
2492 case ICoreSettings::ProxyType::ptSOCKS5:
2493 case ICoreSettings::ProxyType::ptHTTP:
2494 return proxyType;
2495 default:
2496 qWarning() << "Repairing invalid ProxyType, UDP will be enabled";
2497 return ICoreSettings::ProxyType::ptNone;
2498 }
2499 }
2500