3#include <QtCore/QSettings>
12 migrateLegacyOperatorID();
15 operatorIDEU()->metaData()->setCustomCookedValidator(&RemoteIDSettings::_euOperatorIDCookedValidator);
18 connect(operatorIDFAA(), &
Fact::rawValueChanged,
this, &RemoteIDSettings::_updateOperatorIDValidForRegion);
24 _updateOperatorIDValidForRegion();
25 _updateBasicIDValidity();
36 const QString legacyOperatorIDKey = QStringLiteral(
"operatorID");
37 const QString legacyValidKey = QStringLiteral(
"operatorIDValid");
38 const QString legacyEUValidKey = QStringLiteral(
"operatorIDEUValid");
40 if (qSettings.contains(legacyOperatorIDKey)) {
41 const QString legacyOperatorID = qSettings.value(legacyOperatorIDKey).toString();
42 const bool legacyEUValid = qSettings.value(legacyEUValidKey, qSettings.value(legacyValidKey,
false)).toBool();
44 if (!legacyOperatorID.isEmpty()) {
48 operatorIDEU()->setRawValue(legacyOperatorID.left(16));
50 operatorIDFAA()->setRawValue(legacyOperatorID);
53 qSettings.remove(legacyOperatorIDKey);
55 qSettings.remove(legacyValidKey);
56 qSettings.remove(legacyEUValidKey);
61QString RemoteIDSettings::_euOperatorIDCookedValidator(
const QVariant& cookedValue)
64 const QString candidate = cookedValue.toString();
67 if (candidate.isEmpty() || (candidate == settings->operatorIDEU()->rawValue().toString())) {
71 if (_isEUOperatorIDValid(candidate)) {
74 return tr(
"Invalid Operator ID. Enter the full 19 or 20 character ID including the 3 secret characters.");
77void RemoteIDSettings::_operatorIDEUChanged()
79 if (_updatingOperatorID) {
85 const QString currentOperatorID = operatorIDEU()->rawValue().toString();
86 if ((currentOperatorID.length() > 16) && _isEUOperatorIDValid(currentOperatorID)) {
87 _updatingOperatorID =
true;
88 operatorIDEU()->setRawValue(currentOperatorID.sliced(0, 16));
89 _updatingOperatorID =
false;
92 _updateOperatorIDValidForRegion();
95void RemoteIDSettings::_regionChanged()
97 const int newRegion = region()->rawValue().toInt();
101 sendOperatorID()->setRawValue(
true);
107 _updateOperatorIDValidForRegion();
110void RemoteIDSettings::_updateOperatorIDValidForRegion()
112 const bool isEURegion = (region()->rawValue().toInt() ==
static_cast<int>(
RegionOperation::EU));
113 const QString currentOperatorID = (isEURegion ? operatorIDEU() : operatorIDFAA())->rawValue().toString();
117 const bool validForRegion = !currentOperatorID.isEmpty();
119 if (_operatorIDValidForRegion != validForRegion) {
120 _operatorIDValidForRegion = validForRegion;
125void RemoteIDSettings::_updateBasicIDValidity()
128 const bool valid = !basicID()->rawValue().toString().isEmpty();
130 if (_basicIDValid != valid) {
131 _basicIDValid = valid;
136bool RemoteIDSettings::_isEUOperatorIDValid(
const QString& operatorID)
140 const bool containsDash = operatorID.contains(
'-');
141 if (!(operatorID.length() == 20 && containsDash) && !(operatorID.length() == 19 && !containsDash)) {
142 qCDebug(RemoteIDSettingsLog) <<
"OperatorID format mismatch: expected 20 chars with dash or 19 chars without";
145 if (containsDash && (operatorID.at(16) !=
'-')) {
146 qCDebug(RemoteIDSettingsLog) <<
"OperatorID dash separator not at expected position";
150 const QString countryCode = operatorID.sliced(0, 3);
151 for (
const QChar& c : countryCode) {
154 if (c < QLatin1Char(
'A') || c > QLatin1Char(
'Z')) {
155 qCDebug(RemoteIDSettingsLog) <<
"OperatorID country code must be 3 uppercase ASCII letters";
160 const QString number = operatorID.sliced(3, 12);
161 const QChar checksum = operatorID.at(15);
162 const QString secret = containsDash ? operatorID.sliced(17, 3) : operatorID.sliced(16, 3);
163 const QString combination = number + secret + checksum;
165 const QString alphabet = QStringLiteral(
"0123456789abcdefghijklmnopqrstuvwxyz");
166 for (
const QChar& c : combination) {
167 if (!alphabet.contains(c)) {
168 qCDebug(RemoteIDSettingsLog) <<
"OperatorID contains characters outside [0-9a-z]";
173 const QChar result = _calculateLuhnMod36(number + secret);
175 const bool valid = (result == checksum);
176 qCDebug(RemoteIDSettingsLog) <<
"Operator ID checksum" << (valid ?
"valid" :
"invalid");
180QChar RemoteIDSettings::_calculateLuhnMod36(
const QString& input)
183 const QString alphabet = QStringLiteral(
"0123456789abcdefghijklmnopqrstuvwxyz");
188 for (
int i = input.length() - 1; i >= 0; i--) {
189 const int codePoint = alphabet.indexOf(input.at(i));
190 int addend = factor * codePoint;
191 factor = (factor == 2) ? 1 : 2;
192 addend = (addend / n) + (addend % n);
196 const int remainder = sum % n;
197 const int checkCodePoint = (n - remainder) % n;
198 return alphabet.at(checkCodePoint);
#define QGC_LOGGING_CATEGORY(name, categoryStr)
#define DECLARE_SETTINGSFACT(CLASS, NAME)
#define DECLARE_SETTINGGROUP(NAME, GROUP)
void rawValueChanged(const QVariant &value)
void basicIDValidChanged()
void migrateLegacyOperatorID()
void operatorIDValidForRegionChanged()
QString settingsGroup() const
static SettingsManager * instance()
RemoteIDSettings * remoteIDSettings() const