1// SPDX-FileCopyrightText: 2016 Kitsune Ral <kitsune-ral@users.sf.net>
2// SPDX-License-Identifier: LGPL-2.1-or-later
3
4#include "settings.h"
5
6#include "logging_categories_p.h"
7#include "util.h"
8
9#include <QtCore/QUrl>
10
11using namespace Quotient;
12
13QString Settings::legacyOrganizationName {};
14QString Settings::legacyApplicationName {};
15
16void Settings::setLegacyNames(const QString& organizationName,
17 const QString& applicationName)
18{
19 legacyOrganizationName = organizationName;
20 legacyApplicationName = applicationName;
21}
22
23Settings::Settings(QObject* parent) : QSettings(parent)
24{
25#if (QT_VERSION < QT_VERSION_CHECK(6, 0, 0))
26 setIniCodec("UTF-8");
27#endif
28}
29
30void Settings::setValue(const QString& key, const QVariant& value)
31{
32 QSettings::setValue(key, value);
33 if (legacySettings.contains(key))
34 legacySettings.remove(key);
35}
36
37void Settings::remove(const QString& key)
38{
39 QSettings::remove(key);
40 if (legacySettings.contains(key))
41 legacySettings.remove(key);
42}
43
44QVariant Settings::value(const QString& key, const QVariant& defaultValue) const
45{
46 auto value = QSettings::value(key, defaultValue: legacySettings.value(key, defaultValue));
47 // QML's Qt.labs.Settings stores boolean values as strings, which, if loaded
48 // through the usual QSettings interface, confuses QML
49 // (QVariant("false") == true in JavaScript). Since we have a mixed
50 // environment where both QSettings and Qt.labs.Settings may potentially
51 // work with same settings, better ensure compatibility.
52 return value.toString() == QStringLiteral("false") ? QVariant(false) : value;
53}
54
55bool Settings::contains(const QString& key) const
56{
57 return QSettings::contains(key) || legacySettings.contains(key);
58}
59
60QStringList Settings::childGroups() const
61{
62 auto groups = QSettings::childGroups();
63 const auto& legacyGroups = legacySettings.childGroups();
64 for (const auto& g: legacyGroups)
65 if (!groups.contains(str: g))
66 groups.push_back(t: g);
67 return groups;
68}
69
70void SettingsGroup::setValue(const QString& key, const QVariant& value)
71{
72 Settings::setValue(key: groupPath + u'/' + key, value);
73}
74
75bool SettingsGroup::contains(const QString& key) const
76{
77 return Settings::contains(key: groupPath + u'/' + key);
78}
79
80QVariant SettingsGroup::value(const QString& key,
81 const QVariant& defaultValue) const
82{
83 return Settings::value(key: groupPath + u'/' + key, defaultValue);
84}
85
86QString SettingsGroup::group() const { return groupPath; }
87
88QStringList SettingsGroup::childGroups() const
89{
90 const_cast<SettingsGroup*>(this)->beginGroup(prefix: groupPath);
91 const_cast<QSettings&>(legacySettings).beginGroup(prefix: groupPath);
92 QStringList l = Settings::childGroups();
93 const_cast<SettingsGroup*>(this)->endGroup();
94 const_cast<QSettings&>(legacySettings).endGroup();
95 return l;
96}
97
98void SettingsGroup::remove(const QString& key)
99{
100 QString fullKey { groupPath };
101 if (!key.isEmpty())
102 fullKey += u'/' + key;
103 Settings::remove(key: fullKey);
104}
105
106QUO_DEFINE_SETTING(AccountSettings, QString, deviceId, "device_id", {},
107 setDeviceId)
108QUO_DEFINE_SETTING(AccountSettings, QString, deviceName, "device_name", {},
109 setDeviceName)
110QUO_DEFINE_SETTING(AccountSettings, bool, keepLoggedIn, "keep_logged_in", false,
111 setKeepLoggedIn)
112
113namespace {
114constexpr auto HomeserverKey = "homeserver"_ls;
115constexpr auto AccessTokenKey = "access_token"_ls;
116constexpr auto EncryptionAccountPickleKey = "encryption_account_pickle"_ls;
117}
118
119QUrl AccountSettings::homeserver() const
120{
121 return QUrl::fromUserInput(userInput: value(key: HomeserverKey).toString());
122}
123
124void AccountSettings::setHomeserver(const QUrl& url)
125{
126 setValue(key: HomeserverKey, value: url.toString());
127}
128
129QString AccountSettings::userId() const { return group().section(asep: u'/', astart: -1); }
130
131void AccountSettings::clearAccessToken()
132{
133 legacySettings.remove(key: AccessTokenKey);
134 legacySettings.remove(QStringLiteral("device_id")); // Force the server to
135 // re-issue it
136 remove(key: AccessTokenKey);
137}
138
139QByteArray AccountSettings::encryptionAccountPickle()
140{
141 return value(key: "encryption_account_pickle"_ls, defaultValue: QString()).toByteArray();
142}
143
144void AccountSettings::setEncryptionAccountPickle(
145 const QByteArray& encryptionAccountPickle)
146{
147 setValue(key: "encryption_account_pickle"_ls, value: encryptionAccountPickle);
148}
149
150void AccountSettings::clearEncryptionAccountPickle()
151{
152 remove(key: EncryptionAccountPickleKey); // TODO: Force to re-issue it?
153}
154