File indexing completed on 2024-12-22 05:16:04

0001 /*
0002     SPDX-FileCopyrightText: 2016-2018 Jan Grulich <jgrulich@redhat.com>
0003     SPDX-FileCopyrightText: 2019 Nicolas Fella <nicolas.fella@gmx.de>
0004     SPDX-FileCopyrightText: 2020 Carson Black <uhhadd@gmail.com>
0005 
0006     SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007 */
0008 
0009 #include "kcm.h"
0010 
0011 // KDE
0012 #include <KLocalizedString>
0013 #include <KPluginFactory>
0014 // Qt
0015 #include <QApplication>
0016 #include <QFileDialog>
0017 #include <QFontMetrics>
0018 #include <QImage>
0019 #include <QQmlProperty>
0020 #include <QQuickItemGrabResult>
0021 #include <QTemporaryFile>
0022 #include <QTimer>
0023 #include <QtQuick/QQuickItem>
0024 
0025 #include "accounts_interface.h"
0026 #include "maskmousearea.h"
0027 #include "user.h"
0028 
0029 Q_LOGGING_CATEGORY(kcm_users, "kcm_users")
0030 
0031 K_PLUGIN_CLASS_WITH_JSON(KCMUser, "kcm_users.json")
0032 
0033 // Work around QTBUG-100458
0034 inline auto asyncCall(OrgFreedesktopAccountsInterface *ptr, const QString &method, const QVariantList &arguments)
0035 {
0036     auto mc = QDBusMessage::createMethodCall(ptr->service(), ptr->path(), ptr->interface(), method);
0037     mc.setArguments(arguments);
0038     mc.setInteractiveAuthorizationAllowed(true);
0039     return QDBusConnection::systemBus().asyncCall(mc);
0040 }
0041 
0042 KCMUser::KCMUser(QObject *parent, const KPluginMetaData &data)
0043     : KQuickConfigModule(parent, data)
0044     , m_dbusInterface(new OrgFreedesktopAccountsInterface(QStringLiteral("org.freedesktop.Accounts"),
0045                                                           QStringLiteral("/org/freedesktop/Accounts"),
0046                                                           QDBusConnection::systemBus(),
0047                                                           this))
0048     , m_model(new UserModel(this))
0049     , m_fingerprintModel(new FingerprintModel(this))
0050 {
0051     constexpr const char *uri = "org.kde.plasma.kcm.users";
0052 
0053     qmlRegisterUncreatableType<UserModel>(uri, 1, 0, "UserModel", QStringLiteral("Registered for enum access only"));
0054     qmlRegisterUncreatableType<User>(uri, 1, 0, "User", QStringLiteral("Use kcm.userModel to access User objects"));
0055     qmlRegisterType<MaskMouseArea>(uri, 1, 0, "MaskMouseArea");
0056 
0057     constexpr const char *uri_fm = "FingerprintModel";
0058 
0059     qmlRegisterUncreatableType<FprintDevice>(uri_fm, 1, 0, "FprintDevice", QStringLiteral("Only for enum access"));
0060     qmlRegisterType<Finger>(uri_fm, 1, 0, "Finger");
0061 
0062     setButtons(Apply);
0063     auto font = QApplication::font("QLabel");
0064     auto fm = QFontMetrics(font);
0065     setColumnWidth(fm.capHeight() * 30);
0066 
0067     const auto dirs = QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("plasma/avatars"), QStandardPaths::LocateDirectory);
0068     for (const auto &dir : dirs) {
0069         QDirIterator it(dir, QStringList{QStringLiteral("*.jpg"), QStringLiteral("*.png")}, QDir::Files, QDirIterator::Subdirectories);
0070 
0071         while (it.hasNext()) {
0072             m_avatarFiles << it.next();
0073         }
0074     }
0075 }
0076 
0077 bool KCMUser::createUser(const QString &name, const QString &realName, const QString &password, bool isAdmin)
0078 {
0079     QDBusPendingReply<QDBusObjectPath> reply = asyncCall(m_dbusInterface, "CreateUser", {name, realName, static_cast<qint32>(isAdmin)});
0080     reply.waitForFinished();
0081     if (reply.isValid()) {
0082         User *createdUser = new User(this);
0083         createdUser->setPath(reply.value());
0084         createdUser->setPassword(password);
0085         delete createdUser;
0086         return true;
0087     }
0088     return false;
0089 }
0090 
0091 bool KCMUser::deleteUser(qint64 id, bool deleteHome)
0092 {
0093     QDBusPendingReply<> reply = asyncCall(m_dbusInterface, "DeleteUser", {id, deleteHome});
0094     reply.waitForFinished();
0095     if (reply.isError()) {
0096         return false;
0097     } else {
0098         return true;
0099     }
0100 }
0101 
0102 KCMUser::~KCMUser()
0103 {
0104 }
0105 
0106 void KCMUser::save()
0107 {
0108     KQuickConfigModule::save();
0109     Q_EMIT apply();
0110 }
0111 
0112 // Grab the initials of a string
0113 QString KCMUser::initializeString(const QString &stringToGrabInitialsOf)
0114 {
0115     if (stringToGrabInitialsOf.isEmpty())
0116         return "";
0117 
0118     auto normalized = stringToGrabInitialsOf.normalized(QString::NormalizationForm_D);
0119     if (normalized.contains(" ")) {
0120         QStringList split = normalized.split(" ");
0121         auto first = split.first();
0122         auto last = split.last();
0123         if (first.isEmpty()) {
0124             return QString(last.front());
0125         }
0126         if (last.isEmpty()) {
0127             return QString(first.front());
0128         }
0129         return QString(first.front()) + last.front();
0130     } else {
0131         return QString(normalized.front());
0132     }
0133 }
0134 
0135 QString KCMUser::plonkImageInTempfile(const QImage &image)
0136 {
0137     auto file = new QTemporaryFile(qApp);
0138     if (file->open()) {
0139         image.save(file, "PNG");
0140     }
0141     return file->fileName();
0142 }
0143 
0144 QUrl KCMUser::recolorSVG(const QUrl &url, const QColor &color)
0145 {
0146     static QMap<QUrl, QString> s_cache;
0147 
0148     if (!s_cache.contains(url)) {
0149         QFile at(url.toString().sliced(QLatin1String("qrc").size()));
0150         if (at.fileName().isEmpty() || !at.open(QFile::ReadOnly)) {
0151             return QUrl();
0152         }
0153         s_cache[url] = QString::fromUtf8(at.readAll());
0154     }
0155 
0156     auto str = s_cache[url];
0157     str.replace("fill:#000000", "fill:" + color.name());
0158     return QUrl("data:image/svg+xml;utf8," + QUrl::toPercentEncoding(str));
0159 }
0160 
0161 void KCMUser::load()
0162 {
0163     Q_EMIT reset();
0164 }
0165 
0166 #include "kcm.moc"