File indexing completed on 2024-05-19 05:57:13
0001 /* 0002 * SPDX-FileCopyrightText: 2019 Jonah BrĂ¼chert <jbb@kaidan.im> 0003 * SPDX-FileCopyrightText: 2019 Simon Schmeisser <s.schmeisser@gmx.net> 0004 * SPDX-FileCopyrightText: 2020 Nicolas Fella <nicolas.fella@gmx.de> 0005 * 0006 * SPDX-License-Identifier: GPL-3.0-or-later 0007 */ 0008 0009 #include "config-qrca.h" 0010 #include <QtGlobal> 0011 0012 #ifndef Q_OS_ANDROID 0013 #include <KService> 0014 #include <KIO/ApplicationLauncherJob> 0015 #endif 0016 0017 #if HAVE_NETWORKMANAGER 0018 #include <NetworkManagerQt/Manager> 0019 #include <NetworkManagerQt/Security8021xSetting> 0020 #include <NetworkManagerQt/Settings> 0021 #include <NetworkManagerQt/WirelessSetting> 0022 #include <NetworkManagerQt/WirelessSecuritySetting> 0023 #endif 0024 0025 #include <QClipboard> 0026 #include <QCryptographicHash> 0027 #include <QDateTime> 0028 #include <QDebug> 0029 #include <QDir> 0030 #include <QGuiApplication> 0031 #include <QImage> 0032 #include <QMimeData> 0033 #include <QStandardPaths> 0034 #include <QTemporaryFile> 0035 0036 #include <KContacts/Addressee> 0037 #include <KContacts/VCardConverter> 0038 #include <KLocalizedString> 0039 0040 #include "Qrca.h" 0041 #include "QrCodeContent.h" 0042 #include "mecardparser.h" 0043 0044 Qrca::Qrca() = default; 0045 0046 KAboutData Qrca::aboutData() const noexcept 0047 { 0048 return m_aboutData; 0049 } 0050 0051 void Qrca::setAboutData(const KAboutData &aboutData) noexcept 0052 { 0053 m_aboutData = aboutData; 0054 0055 Q_EMIT aboutDataChanged(); 0056 } 0057 0058 QString Qrca::encodeText() const noexcept 0059 { 0060 return m_encodeText; 0061 } 0062 0063 void Qrca::setEncodeText(const QString &encodeText) noexcept 0064 { 0065 m_encodeText = encodeText; 0066 0067 Q_EMIT encodeTextChanged(); 0068 } 0069 0070 void Qrca::saveVCard(const QString &text) noexcept 0071 { 0072 QString path = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/kpeoplevcard"); 0073 0074 QCryptographicHash hash(QCryptographicHash::Sha1); 0075 hash.addData(getVCardName(text).toUtf8()); 0076 0077 QFile file(path + QStringLiteral("/") + QString::fromLatin1(hash.result().toHex()) + QStringLiteral(".vcf")); 0078 0079 if (!file.open(QFile::WriteOnly)) { 0080 qWarning() << "Couldn't save vCard: Couldn't open file for writing."; 0081 return; 0082 } 0083 file.write(text.toUtf8(), text.toUtf8().length()); 0084 file.close(); 0085 } 0086 0087 QString Qrca::getVCardName(const QString &text) noexcept 0088 { 0089 KContacts::VCardConverter converter; 0090 KContacts::Addressee adressee = converter.parseVCard(text.toUtf8()); 0091 0092 return adressee.realName(); 0093 } 0094 0095 QString Qrca::newQrCodeSaveLocation() noexcept 0096 { 0097 const QString directory = QStandardPaths::writableLocation(QStandardPaths::TempLocation); 0098 const QString path = directory + QDir::separator() + QDateTime::currentDateTime().toString(Qt::ISODate) + QStringLiteral(".png"); 0099 return path; 0100 } 0101 0102 void Qrca::copyToClipboard(const QrCodeContent &content) noexcept 0103 { 0104 QClipboard *clipboard = QGuiApplication::clipboard(); 0105 if (!content.isPlainText()) { 0106 auto md = new QMimeData; 0107 md->setData(QStringLiteral("application/octet-stream"), content.binaryContent()); 0108 clipboard->setMimeData(md); 0109 } else { 0110 clipboard->setText(content.text()); 0111 } 0112 } 0113 0114 bool Qrca::hasApplication(const QString &appId) const 0115 { 0116 #ifndef Q_OS_ANDROID 0117 return KService::serviceByDesktopName(appId); 0118 #else 0119 return false; 0120 #endif 0121 } 0122 0123 QString Qrca::applicationIconName(const QString &appId) const 0124 { 0125 #ifndef Q_OS_ANDROID 0126 const auto service = KService::serviceByDesktopName(appId); 0127 return service ? service->icon() : QString(); 0128 #else 0129 return {}; 0130 #endif 0131 } 0132 0133 void Qrca::openInApplication(const QrCodeContent &content, const QString &appId) 0134 { 0135 #ifndef Q_OS_ANDROID 0136 QTemporaryFile file; 0137 if (!file.open()) { 0138 qWarning() << file.errorString(); 0139 return; 0140 } 0141 if (content.isPlainText()) { 0142 file.write(content.text().toUtf8()); 0143 } else { 0144 file.write(content.binaryContent()); 0145 } 0146 file.flush(); 0147 file.setAutoRemove(false); 0148 0149 auto job = new KIO::ApplicationLauncherJob(KService::serviceByDesktopName(appId), this); 0150 job->setUrls({QUrl::fromLocalFile(file.fileName())}); 0151 job->setRunFlags(KIO::ApplicationLauncherJob::DeleteTemporaryFiles); 0152 job->start(); 0153 #endif 0154 } 0155 0156 QString Qrca::wifiName(const QString& wifiSetting) const 0157 { 0158 MeCardParser p; 0159 p.parse(wifiSetting); 0160 return p.value(u"S"); 0161 } 0162 0163 bool Qrca::canConnectToWifi() const 0164 { 0165 #if HAVE_NETWORKMANAGER 0166 return NetworkManager::isNetworkingEnabled(); 0167 #else 0168 return false; 0169 #endif 0170 } 0171 0172 // see https://github.com/zxing/zxing/blob/master/android/src/com/google/zxing/client/android/wifi/WifiConfigManager.java 0173 // for the details not found in the documentation 0174 #if HAVE_NETWORKMANAGER 0175 static struct { 0176 const char *name; 0177 NetworkManager::Security8021xSetting::EapMethod method; 0178 } constexpr const eap_methods[] = { 0179 { "PEAP", NetworkManager::Security8021xSetting::EapMethodPeap }, 0180 { "PWD", NetworkManager::Security8021xSetting::EapMethodPwd }, 0181 { "TLS", NetworkManager::Security8021xSetting::EapMethodTls }, 0182 { "TTLS", NetworkManager::Security8021xSetting::EapMethodTtls }, 0183 }; 0184 0185 static struct { 0186 const char *name; 0187 NetworkManager::Security8021xSetting::AuthMethod method; 0188 } constexpr const auth_methods[] = { 0189 { "GTC", NetworkManager::Security8021xSetting::AuthMethodGtc }, 0190 { "MSCHAP", NetworkManager::Security8021xSetting::AuthMethodMschap }, 0191 { "MSCHAPV2", NetworkManager::Security8021xSetting::AuthMethodMschapv2 }, 0192 { "PAP", NetworkManager::Security8021xSetting::AuthMethodPap }, 0193 }; 0194 #endif 0195 0196 void Qrca::connectToWifi(const QString &wifiCode) 0197 { 0198 MeCardParser p; 0199 p.parse(wifiCode); 0200 0201 #if HAVE_NETWORKMANAGER 0202 using namespace NetworkManager; 0203 auto settings = ConnectionSettings::Ptr(new ConnectionSettings(ConnectionSettings::Wireless)); 0204 settings->setId(p.value(u"S")); 0205 settings->setUuid(ConnectionSettings::createNewUuid()); 0206 settings->setAutoconnect(true); 0207 0208 auto wifiSetting = settings->setting(Setting::Wireless).dynamicCast<WirelessSetting>(); 0209 wifiSetting->setInitialized(true); 0210 wifiSetting = settings->setting(Setting::Wireless).dynamicCast<WirelessSetting>(); 0211 wifiSetting->setSsid(p.value(u"S").toUtf8()); 0212 0213 auto wifiSecurity = settings->setting(Setting::WirelessSecurity).dynamicCast<WirelessSecuritySetting>(); 0214 const auto securityType = p.value(u"T"); 0215 0216 if (!securityType.isEmpty() && securityType != QLatin1String("nopass")) { 0217 wifiSecurity->setInitialized(true); 0218 wifiSetting->setSecurity(QStringLiteral("802-11-wireless-security")); 0219 } 0220 0221 if (securityType == QLatin1String("WPA") || securityType == QLatin1String("WEP")) { 0222 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk); 0223 wifiSecurity->setPsk(p.value(u"P")); 0224 wifiSecurity->setPskFlags(NetworkManager::Setting::AgentOwned); 0225 } else if (securityType == QLatin1String("WPA2-EAP")) { 0226 wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap); 0227 auto sec8021x = settings->setting(Setting::Security8021x).dynamicCast<Security8021xSetting>(); 0228 sec8021x->setAnonymousIdentity(p.value(u"A")); 0229 sec8021x->setIdentity(p.value(u"I")); 0230 sec8021x->setPassword(p.value(u"P")); 0231 0232 const auto eapMethod = p.value(u"E"); 0233 for (const auto &method : eap_methods) { 0234 if (eapMethod == QLatin1String(method.name)) { 0235 sec8021x->setEapMethods({method.method}); 0236 break; 0237 } 0238 } 0239 const auto phase2AuthMethod = p.value(u"PH2"); 0240 for (const auto &method : auth_methods) { 0241 if (phase2AuthMethod == QLatin1String(method.name)) { 0242 sec8021x->setPhase2AuthMethod(method.method); 0243 break; 0244 } 0245 } 0246 } 0247 0248 NetworkManager::addConnection(settings->toMap()); 0249 #endif 0250 } 0251 0252 QrCodeContent Qrca::resultContent(const Prison::ScanResult &result) 0253 { 0254 if (result.hasBinaryData()) { 0255 return QrCodeContent(result.binaryData(), result.format()); 0256 } else { 0257 return QrCodeContent(result.text(), result.format()); 0258 } 0259 }