File indexing completed on 2022-09-27 15:54:08

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 QUrl Qrca::save(const QImage &image) noexcept
0096 {
0097     const QString directory = QStandardPaths::writableLocation(QStandardPaths::PicturesLocation) + QStringLiteral("/qrcodes/");
0098 
0099     const QString path = directory + QDateTime::currentDateTime().toString(Qt::ISODate) + QStringLiteral(".png");
0100 
0101     const QDir dir(directory);
0102     if (!dir.exists()) {
0103         dir.mkpath(directory);
0104     }
0105 
0106     qDebug() << "Saving image to" << path;
0107     image.save(path, "PNG", -1);
0108 
0109     return QUrl::fromLocalFile(path);
0110 }
0111 
0112 void Qrca::copyToClipboard(const QrCodeContent &content) noexcept
0113 {
0114     QClipboard *clipboard = QGuiApplication::clipboard();
0115     if (!content.isPlainText()) {
0116         auto md = new QMimeData;
0117         md->setData(QStringLiteral("application/octet-stream"), content.binaryContent());
0118         clipboard->setMimeData(md);
0119     } else {
0120         clipboard->setText(content.text());
0121     }
0122 }
0123 
0124 bool Qrca::hasApplication(const QString &appId) const
0125 {
0126 #ifndef Q_OS_ANDROID
0127     return KService::serviceByDesktopName(appId);
0128 #else
0129     return false;
0130 #endif
0131 }
0132 
0133 QString Qrca::applicationIconName(const QString &appId) const
0134 {
0135 #ifndef Q_OS_ANDROID
0136     const auto service = KService::serviceByDesktopName(appId);
0137     return service ? service->icon() : QString();
0138 #else
0139     return {};
0140 #endif
0141 }
0142 
0143 void Qrca::openInApplication(const QrCodeContent &content, const QString &appId)
0144 {
0145 #ifndef Q_OS_ANDROID
0146     QTemporaryFile file;
0147     if (!file.open()) {
0148         qWarning() << file.errorString();
0149         return;
0150     }
0151     if (content.isPlainText()) {
0152         file.write(content.text().toUtf8());
0153     } else {
0154         file.write(content.binaryContent());
0155     }
0156     file.flush();
0157     file.setAutoRemove(false);
0158 
0159     auto job = new KIO::ApplicationLauncherJob(KService::serviceByDesktopName(appId), this);
0160     job->setUrls({QUrl::fromLocalFile(file.fileName())});
0161     job->setRunFlags(KIO::ApplicationLauncherJob::DeleteTemporaryFiles);
0162     job->start();
0163 #endif
0164 }
0165 
0166 QString Qrca::wifiName(const QString& wifiSetting) const
0167 {
0168     MeCardParser p;
0169     p.parse(wifiSetting);
0170     return p.value(u"S");
0171 }
0172 
0173 bool Qrca::canConnectToWifi() const
0174 {
0175 #if HAVE_NETWORKMANAGER
0176     return NetworkManager::isNetworkingEnabled();
0177 #else
0178     return false;
0179 #endif
0180 }
0181 
0182 // see https://github.com/zxing/zxing/blob/master/android/src/com/google/zxing/client/android/wifi/WifiConfigManager.java
0183 // for the details not found in the documentation
0184 #if HAVE_NETWORKMANAGER
0185 static struct {
0186     const char *name;
0187     NetworkManager::Security8021xSetting::EapMethod method;
0188 } constexpr const eap_methods[] = {
0189     { "PEAP", NetworkManager::Security8021xSetting::EapMethodPeap },
0190     { "PWD", NetworkManager::Security8021xSetting::EapMethodPwd },
0191     { "TLS", NetworkManager::Security8021xSetting::EapMethodTls },
0192     { "TTLS", NetworkManager::Security8021xSetting::EapMethodTtls },
0193 };
0194 
0195 static struct {
0196     const char *name;
0197     NetworkManager::Security8021xSetting::AuthMethod method;
0198 } constexpr const auth_methods[] = {
0199     { "GTC", NetworkManager::Security8021xSetting::AuthMethodGtc },
0200     { "MSCHAP", NetworkManager::Security8021xSetting::AuthMethodMschap },
0201     { "MSCHAPV2", NetworkManager::Security8021xSetting::AuthMethodMschapv2 },
0202     { "PAP", NetworkManager::Security8021xSetting::AuthMethodPap },
0203 };
0204 #endif
0205 
0206 void Qrca::connectToWifi(const QString &wifiCode)
0207 {
0208     MeCardParser p;
0209     p.parse(wifiCode);
0210 
0211 #if HAVE_NETWORKMANAGER
0212     using namespace NetworkManager;
0213     auto settings = ConnectionSettings::Ptr(new ConnectionSettings(ConnectionSettings::Wireless));
0214     settings->setId(p.value(u"S"));
0215     settings->setUuid(ConnectionSettings::createNewUuid());
0216     settings->setAutoconnect(true);
0217 
0218     auto wifiSetting = settings->setting(Setting::Wireless).dynamicCast<WirelessSetting>();
0219     wifiSetting->setInitialized(true);
0220     wifiSetting = settings->setting(Setting::Wireless).dynamicCast<WirelessSetting>();
0221     wifiSetting->setSsid(p.value(u"S").toUtf8());
0222 
0223     auto wifiSecurity = settings->setting(Setting::WirelessSecurity).dynamicCast<WirelessSecuritySetting>();
0224     const auto securityType = p.value(u"T");
0225 
0226     if (!securityType.isEmpty() && securityType != QLatin1String("nopass")) {
0227         wifiSecurity->setInitialized(true);
0228         wifiSetting->setSecurity(QStringLiteral("802-11-wireless-security"));
0229     }
0230 
0231     if (securityType == QLatin1String("WPA") || securityType == QLatin1String("WEP")) {
0232         wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaPsk);
0233         wifiSecurity->setPsk(p.value(u"P"));
0234         wifiSecurity->setPskFlags(NetworkManager::Setting::AgentOwned);
0235     } else if (securityType == QLatin1String("WPA2-EAP")) {
0236         wifiSecurity->setKeyMgmt(NetworkManager::WirelessSecuritySetting::WpaEap);
0237         auto sec8021x = settings->setting(Setting::Security8021x).dynamicCast<Security8021xSetting>();
0238         sec8021x->setAnonymousIdentity(p.value(u"A"));
0239         sec8021x->setIdentity(p.value(u"I"));
0240         sec8021x->setPassword(p.value(u"P"));
0241 
0242         const auto eapMethod = p.value(u"E");
0243         for (const auto &method : eap_methods) {
0244             if (eapMethod == QLatin1String(method.name)) {
0245                 sec8021x->setEapMethods({method.method});
0246                 break;
0247             }
0248         }
0249         const auto phase2AuthMethod = p.value(u"PH2");
0250         for (const auto &method : auth_methods) {
0251             if (phase2AuthMethod == QLatin1String(method.name)) {
0252                 sec8021x->setPhase2AuthMethod(method.method);
0253                 break;
0254             }
0255         }
0256     }
0257 
0258     NetworkManager::addConnection(settings->toMap());
0259 #endif
0260 }
0261 
0262 QrCodeContent Qrca::resultContent(const Prison::ScanResult &result)
0263 {
0264     if (result.hasBinaryData()) {
0265         return QrCodeContent(result.binaryData(), result.format());
0266     } else {
0267         return QrCodeContent(result.text(), result.format());
0268     }
0269 }