File indexing completed on 2024-12-01 08:10:07
0001 /* 0002 SPDX-FileCopyrightText: 2010-2012 Lamarque Souza <lamarque@kde.org> 0003 0004 SPDX-License-Identifier: GPL-2.0-only OR GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL 0005 */ 0006 0007 #include "mobileproviders.h" 0008 #include "plasma_nm_editor.h" 0009 0010 #include <QFile> 0011 #include <QLocale> 0012 #include <QRegularExpression> 0013 #include <QTextStream> 0014 0015 const QString MobileProviders::ProvidersFile = QStringLiteral(BROADBANDPROVIDER_DATABASE); 0016 0017 bool localeAwareCompare(const QString &one, const QString &two) 0018 { 0019 return one.localeAwareCompare(two) < 0; 0020 } 0021 0022 MobileProviders::MobileProviders() 0023 { 0024 for (int c = 1; c <= QLocale::LastCountry; c++) { 0025 const auto country = static_cast<QLocale::Country>(c); 0026 QLocale locale(QLocale::AnyLanguage, country); 0027 if (locale.country() == country) { 0028 const QString localeName = locale.name(); 0029 const auto idx = localeName.indexOf(QLatin1Char('_')); 0030 if (idx != -1) { 0031 const QString countryCode = localeName.mid(idx + 1); 0032 QString countryName = locale.nativeCountryName(); 0033 if (countryName.isEmpty()) { 0034 countryName = QLocale::countryToString(country); 0035 } 0036 mCountries.insert(countryCode, countryName); 0037 } 0038 } 0039 } 0040 mError = Success; 0041 0042 QFile file2(ProvidersFile); 0043 0044 if (file2.open(QIODevice::ReadOnly)) { 0045 if (mDocProviders.setContent(&file2)) { 0046 docElement = mDocProviders.documentElement(); 0047 0048 if (docElement.isNull()) { 0049 qCWarning(PLASMA_NM_EDITOR_LOG) << ProvidersFile << ": document is null"; 0050 mError = ProvidersIsNull; 0051 } else { 0052 if (docElement.isNull() || docElement.tagName() != QLatin1String("serviceproviders")) { 0053 qCWarning(PLASMA_NM_EDITOR_LOG) << ProvidersFile << ": wrong format"; 0054 mError = ProvidersWrongFormat; 0055 } else { 0056 if (docElement.attribute(QStringLiteral("format")) != QLatin1String("2.0")) { 0057 qCWarning(PLASMA_NM_EDITOR_LOG) << ProvidersFile << ": mobile broadband provider database format '" 0058 << docElement.attribute(QStringLiteral("format")) << "' not supported."; 0059 mError = ProvidersFormatNotSupported; 0060 } else { 0061 // qCDebug(PLASMA_NM_EDITOR_LOG) << "Everything is alright so far"; 0062 } 0063 } 0064 } 0065 } 0066 0067 file2.close(); 0068 } else { 0069 qCWarning(PLASMA_NM_EDITOR_LOG) << "Error opening providers file" << ProvidersFile; 0070 mError = ProvidersMissing; 0071 } 0072 } 0073 0074 MobileProviders::~MobileProviders() = default; 0075 0076 QStringList MobileProviders::getCountryList() const 0077 { 0078 QStringList temp = mCountries.values(); 0079 std::sort(temp.begin(), temp.end(), localeAwareCompare); 0080 return temp; 0081 } 0082 0083 QString MobileProviders::countryFromLocale() const 0084 { 0085 const QString localeName = QLocale().name(); 0086 const auto idx = localeName.indexOf(QLatin1Char('_')); 0087 if (idx != -1) { 0088 return localeName.mid(idx + 1); 0089 } 0090 return {}; 0091 } 0092 0093 QStringList MobileProviders::getProvidersList(QString country, NetworkManager::ConnectionSettings::ConnectionType type) 0094 { 0095 mProvidersGsm.clear(); 0096 mProvidersCdma.clear(); 0097 QDomNode n = docElement.firstChild(); 0098 0099 // country is a country name and we parse country codes. 0100 if (!mCountries.key(country).isNull()) { 0101 country = mCountries.key(country); 0102 } 0103 QMap<QString, QString> sortedGsm; 0104 QMap<QString, QString> sortedCdma; 0105 while (!n.isNull()) { 0106 QDomElement e = n.toElement(); // <country ...> 0107 0108 if (!e.isNull() && e.attribute(QStringLiteral("code")).toUpper() == country) { 0109 QDomNode n2 = e.firstChild(); 0110 while (!n2.isNull()) { 0111 QDomElement e2 = n2.toElement(); // <provider ...> 0112 0113 if (!e2.isNull() && e2.tagName().toLower() == QLatin1String("provider")) { 0114 QDomNode n3 = e2.firstChild(); 0115 bool hasGsm = false; 0116 bool hasCdma = false; 0117 QMap<QString, QString> localizedProviderNames; 0118 0119 while (!n3.isNull()) { 0120 QDomElement e3 = n3.toElement(); // <name | gsm | cdma> 0121 0122 if (!e3.isNull()) { 0123 if (e3.tagName().toLower() == QLatin1String("gsm")) { 0124 hasGsm = true; 0125 } else if (e3.tagName().toLower() == QLatin1String("cdma")) { 0126 hasCdma = true; 0127 } else if (e3.tagName().toLower() == QLatin1String("name")) { 0128 QString lang = e3.attribute(QStringLiteral("xml:lang")); 0129 if (lang.isEmpty()) { 0130 lang = QStringLiteral("en"); // English is default 0131 } else { 0132 lang = lang.toLower(); 0133 lang.remove(QRegularExpression(QStringLiteral("\\-.*$"))); // Remove everything after '-' in xml:lang attribute. 0134 } 0135 localizedProviderNames.insert(lang, e3.text()); 0136 } 0137 } 0138 n3 = n3.nextSibling(); 0139 } 0140 const QString name = getNameByLocale(localizedProviderNames); 0141 if (hasGsm) { 0142 mProvidersGsm.insert(name, e2.firstChild()); 0143 sortedGsm.insert(name.toLower(), name); 0144 } 0145 if (hasCdma) { 0146 mProvidersCdma.insert(name, e2.firstChild()); 0147 sortedCdma.insert(name.toLower(), name); 0148 } 0149 } 0150 n2 = n2.nextSibling(); 0151 } 0152 break; 0153 } 0154 n = n.nextSibling(); 0155 } 0156 0157 if (type == NetworkManager::ConnectionSettings::Gsm) { 0158 return sortedGsm.values(); 0159 } 0160 return sortedCdma.values(); 0161 } 0162 0163 QStringList MobileProviders::getApns(const QString &provider) 0164 { 0165 mApns.clear(); 0166 mNetworkIds.clear(); 0167 if (!mProvidersGsm.contains(provider)) { 0168 return {}; 0169 } 0170 0171 QDomNode n = mProvidersGsm[provider]; 0172 0173 while (!n.isNull()) { 0174 QDomElement e = n.toElement(); // <gsm | cdma> 0175 0176 if (!e.isNull() && e.tagName().toLower() == QLatin1String("gsm")) { 0177 QDomNode n2 = e.firstChild(); 0178 while (!n2.isNull()) { 0179 QDomElement e2 = n2.toElement(); // <apn | network-id> 0180 0181 if (!e2.isNull() && e2.tagName().toLower() == QLatin1String("apn")) { 0182 bool isInternet = true; 0183 QDomNode n3 = e2.firstChild(); 0184 while (!n3.isNull()) { 0185 QDomElement e3 = n3.toElement(); // <usage> 0186 if (!e3.isNull() && e3.tagName().toLower() == QLatin1String("usage") && !e3.attribute(QStringLiteral("type")).isNull() 0187 && e3.attribute(QStringLiteral("type")).toLower() != QLatin1String("internet")) { 0188 // qCDebug(PLASMA_NM_EDITOR_LOG) << "apn" << e2.attribute("value") << "ignored because of usage" << e3.attribute("type"); 0189 isInternet = false; 0190 break; 0191 } 0192 n3 = n3.nextSibling(); 0193 } 0194 if (isInternet) { 0195 mApns.insert(e2.attribute(QStringLiteral("value")), e2.firstChild()); 0196 } 0197 } else if (!e2.isNull() && e2.tagName().toLower() == QLatin1String("network-id")) { 0198 mNetworkIds.append(e2.attribute(QStringLiteral("mcc")) + '-' + e2.attribute(QStringLiteral("mnc"))); 0199 } 0200 0201 n2 = n2.nextSibling(); 0202 } 0203 } 0204 n = n.nextSibling(); 0205 } 0206 0207 QStringList temp = mApns.keys(); 0208 temp.sort(); 0209 return temp; 0210 } 0211 0212 ProviderData MobileProviders::parseProvider(const QDomNode &providerNode) 0213 { 0214 ProviderData result; 0215 0216 QMap<QString, QString> localizedProviderNames; 0217 0218 QDomNode c = providerNode.firstChild(); // <name | gsm | cdma> 0219 0220 while (!c.isNull()) { 0221 QDomElement ce = c.toElement(); 0222 0223 if (ce.tagName().toLower() == QLatin1String("gsm")) { 0224 QDomNode gsmNode = c.firstChild(); 0225 0226 while (!gsmNode.isNull()) { 0227 QDomElement gsmElement = gsmNode.toElement(); 0228 0229 if (gsmElement.tagName().toLower() == QLatin1String("network-id")) { 0230 result.mccmncs.append(gsmElement.attribute(QStringLiteral("mcc")) + gsmElement.attribute(QStringLiteral("mnc"))); 0231 } 0232 gsmNode = gsmNode.nextSibling(); 0233 } 0234 } else if (ce.tagName().toLower() == QLatin1String("name")) { 0235 QString lang = ce.attribute(QStringLiteral("xml:lang")); 0236 if (lang.isEmpty()) { 0237 lang = QStringLiteral("en"); // English is default 0238 } else { 0239 lang = lang.toLower(); 0240 lang.remove(QRegularExpression(QStringLiteral("\\-.*$"))); // Remove everything after '-' in xml:lang attribute. 0241 } 0242 localizedProviderNames.insert(lang, ce.text()); 0243 } 0244 c = c.nextSibling(); 0245 } 0246 0247 result.name = getNameByLocale(localizedProviderNames); 0248 0249 return result; 0250 } 0251 0252 QStringList MobileProviders::getProvidersFromMCCMNC(const QString &targetMccMnc) 0253 { 0254 QStringList result; 0255 0256 QDomNode n = docElement.firstChild(); 0257 0258 while (!n.isNull()) { 0259 QDomElement e = n.toElement(); // <country ...> 0260 0261 if (!e.isNull()) { 0262 QDomNode n2 = e.firstChild(); 0263 while (!n2.isNull()) { 0264 QDomElement e2 = n2.toElement(); // <provider ...> 0265 0266 if (!e2.isNull() && e2.tagName().toLower() == QLatin1String("provider")) { 0267 ProviderData data = parseProvider(e2); 0268 0269 if (data.mccmncs.contains(targetMccMnc)) { 0270 result << data.name; 0271 } 0272 } 0273 n2 = n2.nextSibling(); 0274 } 0275 } 0276 n = n.nextSibling(); 0277 } 0278 0279 return result; 0280 } 0281 0282 QStringList MobileProviders::getNetworkIds(const QString &provider) 0283 { 0284 if (mNetworkIds.isEmpty()) { 0285 getApns(provider); 0286 } 0287 return mNetworkIds; 0288 } 0289 0290 QVariantMap MobileProviders::getApnInfo(const QString &apn) 0291 { 0292 QVariantMap temp; 0293 QDomNode n = mApns[apn]; 0294 QStringList dnsList; 0295 QMap<QString, QString> localizedPlanNames; 0296 0297 while (!n.isNull()) { 0298 QDomElement e = n.toElement(); // <name|username|password|dns(*)> 0299 0300 if (!e.isNull()) { 0301 if (e.tagName().toLower() == QLatin1String("name")) { 0302 QString lang = e.attribute(QStringLiteral("xml:lang")); 0303 if (lang.isEmpty()) { 0304 lang = QStringLiteral("en"); // English is default 0305 } else { 0306 lang = lang.toLower(); 0307 lang.remove(QRegularExpression(QStringLiteral("\\-.*$"))); // Remove everything after '-' in xml:lang attribute. 0308 } 0309 localizedPlanNames.insert(lang, e.text()); 0310 } else if (e.tagName().toLower() == QLatin1String("username")) { 0311 temp.insert(QStringLiteral("username"), e.text()); 0312 } else if (e.tagName().toLower() == QLatin1String("password")) { 0313 temp.insert(QStringLiteral("password"), e.text()); 0314 } else if (e.tagName().toLower() == QLatin1String("dns")) { 0315 dnsList.append(e.text()); 0316 } 0317 } 0318 0319 n = n.nextSibling(); 0320 } 0321 0322 QString name = getNameByLocale(localizedPlanNames); 0323 if (!name.isEmpty()) { 0324 temp.insert(QStringLiteral("name"), QVariant::fromValue(name)); 0325 } 0326 temp.insert(QStringLiteral("number"), getGsmNumber()); 0327 temp.insert(QStringLiteral("apn"), apn); 0328 temp.insert(QStringLiteral("dnsList"), dnsList); 0329 0330 return temp; 0331 } 0332 0333 QVariantMap MobileProviders::getCdmaInfo(const QString &provider) 0334 { 0335 if (!mProvidersCdma.contains(provider)) { 0336 return {}; 0337 } 0338 0339 QVariantMap temp; 0340 QDomNode n = mProvidersCdma[provider]; 0341 QStringList sidList; 0342 0343 while (!n.isNull()) { 0344 QDomElement e = n.toElement(); // <gsm or cdma ...> 0345 0346 if (!e.isNull() && e.tagName().toLower() == QLatin1String("cdma")) { 0347 QDomNode n2 = e.firstChild(); 0348 while (!n2.isNull()) { 0349 QDomElement e2 = n2.toElement(); // <name | username | password | sid> 0350 0351 if (!e2.isNull()) { 0352 if (e2.tagName().toLower() == QLatin1String("username")) { 0353 temp.insert(QStringLiteral("username"), e2.text()); 0354 } else if (e2.tagName().toLower() == QLatin1String("password")) { 0355 temp.insert(QStringLiteral("password"), e2.text()); 0356 } else if (e2.tagName().toLower() == QLatin1String("sid")) { 0357 sidList.append(e2.text()); 0358 } 0359 } 0360 0361 n2 = n2.nextSibling(); 0362 } 0363 } 0364 n = n.nextSibling(); 0365 } 0366 0367 temp.insert(QStringLiteral("number"), getCdmaNumber()); 0368 temp.insert(QStringLiteral("sidList"), sidList); 0369 return temp; 0370 } 0371 0372 QString MobileProviders::getNameByLocale(const QMap<QString, QString> &localizedNames) const 0373 { 0374 QString name; 0375 const QStringList locales = QLocale().uiLanguages(); 0376 for (const QString &locale : locales) { 0377 QString language = locale.split(QLatin1Char('-')).at(0); 0378 0379 if (localizedNames.contains(language)) { 0380 return localizedNames[language]; 0381 } 0382 } 0383 0384 name = localizedNames[QStringLiteral("en")]; 0385 0386 // Use any language if no proper localized name were found. 0387 if (name.isEmpty() && !localizedNames.isEmpty()) { 0388 name = localizedNames.constBegin().value(); 0389 } 0390 return name; 0391 }