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 }