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