File indexing completed on 2024-05-05 17:33:37

0001 /**
0002  * SPDX-FileCopyrightText: 2022 Suhaas Joshi <joshiesuhaas0@gmail.com>
0003  * SPDX-FileCopyrightText: 2023 ivan tkachenko <me@ratijas.tk>
0004  * SPDX-License-Identifier: GPL-2.0-or-later
0005  */
0006 
0007 #include "flatpakreference.h"
0008 #include "flatpakhelper.h"
0009 
0010 #ifdef FLATPAK_EXTERNC_REQUIRED
0011 extern "C" {
0012 #endif
0013 #include <flatpak/flatpak.h>
0014 #ifdef FLATPAK_EXTERNC_REQUIRED
0015 }
0016 #endif
0017 #include <glib.h>
0018 
0019 #include <QDebug>
0020 
0021 FlatpakReference::FlatpakReference(FlatpakReferencesModel *parent,
0022                                    const QString &flatpakName,
0023                                    const QString &arch,
0024                                    const QString &branch,
0025                                    const QString &version,
0026                                    const QString &displayName,
0027                                    const QUrl &iconSource,
0028                                    const QStringList &metadataAndOverridesFiles)
0029     : QObject(parent)
0030     , m_flatpakName(flatpakName)
0031     , m_arch(arch)
0032     , m_branch(branch)
0033     , m_version(version)
0034     , m_displayName(displayName)
0035     , m_iconSource(iconSource)
0036     , m_metadataAndOverridesFiles(metadataAndOverridesFiles)
0037     , m_permissionsModel(nullptr)
0038 {
0039     connect(this, &FlatpakReference::needsLoad, parent, &FlatpakReferencesModel::needsLoad);
0040     connect(this, &FlatpakReference::settingsChanged, parent, &FlatpakReferencesModel::settingsChanged);
0041 }
0042 
0043 FlatpakReferencesModel *FlatpakReference::parent() const
0044 {
0045     // SAFETY: There's only one constructor, and it always initializes parent with a model object
0046     return qobject_cast<FlatpakReferencesModel *>(QObject::parent());
0047 }
0048 
0049 QString FlatpakReference::arch() const
0050 {
0051     return m_arch;
0052 }
0053 
0054 QString FlatpakReference::branch() const
0055 {
0056     return m_branch;
0057 }
0058 
0059 QString FlatpakReference::version() const
0060 {
0061     return m_version;
0062 }
0063 
0064 QUrl FlatpakReference::iconSource() const
0065 {
0066     return m_iconSource;
0067 }
0068 
0069 const QStringList &FlatpakReference::metadataAndOverridesFiles() const
0070 {
0071     return m_metadataAndOverridesFiles;
0072 }
0073 
0074 QStringList FlatpakReference::defaultsFiles() const
0075 {
0076     QStringList defaults = m_metadataAndOverridesFiles;
0077     defaults.removeLast();
0078     return defaults;
0079 }
0080 
0081 const QString &FlatpakReference::userLevelPerAppOverrideFile() const
0082 {
0083     return m_metadataAndOverridesFiles.last();
0084 }
0085 
0086 QString FlatpakReference::displayName() const
0087 {
0088     /* sometimes, the application does not seem to have a display name, so return its id */
0089     return m_displayName.isEmpty() ? m_flatpakName : m_displayName;
0090 }
0091 
0092 QString FlatpakReference::flatpakName() const
0093 {
0094     // Reduced implementation of libdiscover, as this KCM lists only installed apps
0095     return m_flatpakName;
0096 }
0097 
0098 QString FlatpakReference::ref() const
0099 {
0100     // KCM lists only apps
0101     return QStringLiteral("app/%1/%2/%3").arg(flatpakName(), arch(), branch());
0102 }
0103 
0104 FlatpakPermissionModel *FlatpakReference::permissionsModel()
0105 {
0106     return m_permissionsModel;
0107 }
0108 
0109 void FlatpakReference::setPermissionsModel(FlatpakPermissionModel *model)
0110 {
0111     if (model != m_permissionsModel) {
0112         if (m_permissionsModel) {
0113             disconnect(m_permissionsModel, &FlatpakPermissionModel::referenceChanged, this, &FlatpakReference::needsLoad);
0114             disconnect(m_permissionsModel, &FlatpakPermissionModel::dataChanged, this, &FlatpakReference::settingsChanged);
0115             disconnect(m_permissionsModel, &FlatpakPermissionModel::rowsInserted, this, &FlatpakReference::settingsChanged);
0116             disconnect(m_permissionsModel, &FlatpakPermissionModel::rowsRemoved, this, &FlatpakReference::settingsChanged);
0117         }
0118         m_permissionsModel = model;
0119         if (m_permissionsModel) {
0120             connect(m_permissionsModel, &FlatpakPermissionModel::referenceChanged, this, &FlatpakReference::needsLoad);
0121             connect(m_permissionsModel, &FlatpakPermissionModel::dataChanged, this, &FlatpakReference::settingsChanged);
0122             connect(m_permissionsModel, &FlatpakPermissionModel::rowsInserted, this, &FlatpakReference::settingsChanged);
0123             connect(m_permissionsModel, &FlatpakPermissionModel::rowsRemoved, this, &FlatpakReference::settingsChanged);
0124         }
0125     }
0126 }
0127 
0128 void FlatpakReference::load()
0129 {
0130     if (m_permissionsModel) {
0131         m_permissionsModel->load();
0132     }
0133 }
0134 
0135 void FlatpakReference::save()
0136 {
0137     if (m_permissionsModel) {
0138         m_permissionsModel->save();
0139     }
0140 }
0141 
0142 void FlatpakReference::defaults()
0143 {
0144     if (m_permissionsModel) {
0145         m_permissionsModel->defaults();
0146     }
0147 }
0148 
0149 bool FlatpakReference::isSaveNeeded() const
0150 {
0151     if (m_permissionsModel) {
0152         return m_permissionsModel->isSaveNeeded();
0153     }
0154     return false;
0155 }
0156 
0157 bool FlatpakReference::isDefaults() const
0158 {
0159     if (m_permissionsModel) {
0160         return m_permissionsModel->isDefaults();
0161     }
0162     return true;
0163 }
0164 
0165 static GPtrArray *getSystemInstalledFlatpakAppRefs()
0166 {
0167     g_autoptr(FlatpakInstallation) installation = flatpak_installation_new_system(nullptr, nullptr);
0168     GPtrArray *refs = flatpak_installation_list_installed_refs_by_kind(installation, FLATPAK_REF_KIND_APP, nullptr, nullptr);
0169     return refs;
0170 }
0171 
0172 static GPtrArray *getUserInstalledFlatpakAppRefs()
0173 {
0174     g_autoptr(FlatpakInstallation) installation = flatpak_installation_new_user(nullptr, nullptr);
0175     GPtrArray *refs = flatpak_installation_list_installed_refs_by_kind(installation, FLATPAK_REF_KIND_APP, nullptr, nullptr);
0176     return refs;
0177 }
0178 
0179 FlatpakReferencesModel::FlatpakReferencesModel(QObject *parent)
0180     : QAbstractListModel(parent)
0181 {
0182     g_autoptr(GPtrArray) systemInstalledRefs = getSystemInstalledFlatpakAppRefs();
0183     g_autoptr(GPtrArray) userInstalledRefs = getUserInstalledFlatpakAppRefs();
0184 
0185     const auto systemOverridesDirectory = FlatpakHelper::systemOverridesDirectory();
0186     const auto userOverridesDirectory = FlatpakHelper::userOverridesDirectory();
0187 
0188     const std::array installedRefs = std::array{systemInstalledRefs, userInstalledRefs};
0189     for (const auto &refs : installedRefs) {
0190         for (uint i = 0; i < refs->len; ++i) {
0191             auto *ref = FLATPAK_REF(g_ptr_array_index(refs, i));
0192             auto *iRef = FLATPAK_INSTALLED_REF(g_ptr_array_index(refs, i));
0193 
0194             const auto flatpakName = QString::fromUtf8(flatpak_ref_get_name(ref));
0195             if (flatpakName.endsWith(QStringLiteral(".BaseApp"))) {
0196                 continue;
0197             }
0198 
0199             const auto arch = QString::fromUtf8(flatpak_ref_get_arch(ref));
0200             const auto branch = QString::fromUtf8(flatpak_ref_get_branch(ref));
0201             const auto version = QString::fromUtf8(flatpak_installed_ref_get_appdata_version(iRef));
0202             const auto displayName = QString::fromUtf8(flatpak_installed_ref_get_appdata_name(iRef));
0203             const auto appBaseDirectory = QString::fromUtf8(flatpak_installed_ref_get_deploy_dir(iRef));
0204             const auto iconSource = FlatpakHelper::iconSourceUrl(displayName, flatpakName, appBaseDirectory);
0205 
0206             const auto metadataPath = (refs == systemInstalledRefs) ? FlatpakHelper::metadataPathForSystemInstallation(flatpakName)
0207                                                                     : FlatpakHelper::metadataPathForUserInstallation(flatpakName);
0208 
0209             const auto systemGlobalOverrides = QStringLiteral("%1/global").arg(systemOverridesDirectory);
0210             const auto systemAppOverrides = QStringLiteral("%1/%2").arg(systemOverridesDirectory, flatpakName);
0211 
0212             const auto userGlobalOverrides = QStringLiteral("%1/global").arg(userOverridesDirectory);
0213             const auto userAppOverrides = QStringLiteral("%1/%2").arg(userOverridesDirectory, flatpakName);
0214 
0215             const auto metadataAndOverridesFiles = QStringList({
0216                 metadataPath,
0217                 systemGlobalOverrides,
0218                 systemAppOverrides,
0219                 userGlobalOverrides,
0220                 userAppOverrides,
0221             });
0222 
0223             m_references.push_back(new FlatpakReference(this, flatpakName, arch, branch, version, displayName, iconSource, metadataAndOverridesFiles));
0224         }
0225     }
0226 
0227     std::sort(m_references.begin(), m_references.end(), [](const FlatpakReference *r1, const FlatpakReference *r2) {
0228         return r1->displayName() < r2->displayName();
0229     });
0230 }
0231 
0232 int FlatpakReferencesModel::rowCount(const QModelIndex &parent) const
0233 {
0234     if (parent.isValid()) {
0235         return 0;
0236     }
0237     return m_references.count();
0238 }
0239 
0240 QVariant FlatpakReferencesModel::data(const QModelIndex &index, int role) const
0241 {
0242     if (!index.isValid()) {
0243         return QVariant();
0244     }
0245 
0246     switch (role) {
0247     case Roles::Name:
0248         return m_references.at(index.row())->displayName();
0249     case Roles::Version:
0250         return m_references.at(index.row())->version();
0251     case Roles::Icon:
0252         return m_references.at(index.row())->iconSource();
0253     case Roles::Ref:
0254         return QVariant::fromValue<FlatpakReference *>(m_references.at(index.row()));
0255     }
0256     return QVariant();
0257 }
0258 
0259 QHash<int, QByteArray> FlatpakReferencesModel::roleNames() const
0260 {
0261     QHash<int, QByteArray> roles;
0262     roles[Roles::Name] = "name";
0263     roles[Roles::Version] = "version";
0264     roles[Roles::Icon] = "icon";
0265     roles[Roles::Ref] = "ref";
0266     return roles;
0267 }
0268 
0269 void FlatpakReferencesModel::load(int index)
0270 {
0271     if (index >= 0 && index < m_references.length()) {
0272         m_references.at(index)->load();
0273     }
0274 }
0275 
0276 void FlatpakReferencesModel::save(int index)
0277 {
0278     if (index >= 0 && index < m_references.length()) {
0279         m_references.at(index)->save();
0280     }
0281 }
0282 
0283 void FlatpakReferencesModel::defaults(int index)
0284 {
0285     if (index >= 0 && index < m_references.length()) {
0286         m_references.at(index)->defaults();
0287     }
0288 }
0289 
0290 bool FlatpakReferencesModel::isSaveNeeded(int index) const
0291 {
0292     if (index >= 0 && index < m_references.length()) {
0293         return m_references.at(index)->isSaveNeeded();
0294     }
0295     return false;
0296 }
0297 
0298 bool FlatpakReferencesModel::isDefaults(int index) const
0299 {
0300     if (index >= 0 && index < m_references.length()) {
0301         return m_references.at(index)->isDefaults();
0302     }
0303     return true;
0304 }
0305 
0306 const QVector<FlatpakReference *> &FlatpakReferencesModel::references() const
0307 {
0308     return m_references;
0309 }