KConfig

kdesktopfile.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 1999 Pietro Iglio <iglio@kde.org>
4 SPDX-FileCopyrightText: 1999 Preston Brown <pbrown@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "kdesktopfile.h"
10
11#include "kauthorized.h"
12#include "kconfig_core_log_settings.h"
13#include "kconfig_p.h"
14#include "kconfiggroup.h"
15#include "kconfigini_p.h"
16#include "kdesktopfileaction.h"
17
18#include <QDir>
19#include <QFileInfo>
20#include <QStandardPaths>
21#include <QUrl>
22
23#ifndef Q_OS_WIN
24#include <unistd.h>
25#endif
26
27#include <algorithm>
28
29class KDesktopFilePrivate : public KConfigPrivate
30{
31public:
32 KDesktopFilePrivate(QStandardPaths::StandardLocation resourceType, const QString &fileName)
33 : KConfigPrivate(KConfig::NoGlobals, resourceType)
34 {
35 changeFileName(fileName);
36 }
37 KConfigGroup desktopGroup;
38};
39
41 : KConfig(*new KDesktopFilePrivate(resourceType, fileName))
42{
45 d->desktopGroup = KConfigGroup(this, QStringLiteral("Desktop Entry"));
46}
47
49 : KDesktopFile(QStandardPaths::ApplicationsLocation, fileName)
50{
51}
52
54
56{
57 Q_D(const KDesktopFile);
58 return d->desktopGroup;
59}
60
62{
63 static const QLatin1Char slash('/');
64
65 // Relative to config? (e.g. for autostart)
67 // Iterate from the last item since some items may be subfolders of others.
68 auto it = std::find_if(genericConfig.crbegin(), genericConfig.crend(), [&path](const QString &dir) {
69 return path.startsWith(dir + slash);
70 });
71 if (it != genericConfig.crend()) {
73 }
74
75 QString relativePath;
76 // Relative to xdg data dir? (much more common)
78 for (const QString &dir : lstGenericDataLocation) {
79 if (path.startsWith(dir + slash)) {
80 relativePath = path.mid(dir.length() + 1);
81 }
82 }
83 if (relativePath.isEmpty()) {
84 // What now? The desktop file doesn't come from XDG_DATA_DIRS. Use filename only and hope for the best.
85 relativePath = path.mid(path.lastIndexOf(slash) + 1);
86 }
88}
89
91{
92 return path.endsWith(QLatin1String(".desktop"));
93}
94
96{
97 if (path.isEmpty()) {
98 return false; // Empty paths are not ok.
99 }
100
101 if (QDir::isRelativePath(path)) {
102 return true; // Relative paths are ok.
103 }
104
105 const QString realPath = QFileInfo(path).canonicalFilePath();
106 if (realPath.isEmpty()) {
107 return false; // File doesn't exist.
108 }
109
110#ifndef Q_OS_WIN
111 static constexpr Qt::CaseSensitivity sensitivity = Qt::CaseSensitive;
112#else
113 static constexpr Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
114#endif
115
116 // Check if the .desktop file is installed as part of KDE or XDG.
118 auto it = std::find_if(appsDirs.cbegin(), appsDirs.cend(), [&realPath](const QString &prefix) {
119 QFileInfo info(prefix);
120 return info.exists() && info.isDir() && realPath.startsWith(info.canonicalFilePath(), sensitivity);
121 });
122 if (it != appsDirs.cend()) {
123 return true;
124 }
125
126 const QString autostartDir = QStringLiteral("autostart/");
128 auto configIt = std::find_if(lstConfigPath.cbegin(), lstConfigPath.cend(), [&realPath, &autostartDir](const QString &xdgDataPrefix) {
129 QFileInfo info(xdgDataPrefix);
130 if (info.exists() && info.isDir()) {
131 const QString prefix = info.canonicalFilePath();
132 return realPath.startsWith(prefix + QLatin1Char('/') + autostartDir, sensitivity);
133 }
134 return false;
135 });
136 if (configIt != lstConfigPath.cend()) {
137 return true;
138 }
139
140 // Forbid desktop files outside of standard locations if kiosk is set so
141 if (!KAuthorized::authorize(QStringLiteral("run_desktop_files"))) {
142 qCWarning(KCONFIG_CORE_LOG) << "Access to" << path << "denied because of 'run_desktop_files' restriction.";
143 return false;
144 }
145
146 // Not otherwise permitted, so only allow if the file is executable, or if
147 // owned by root (uid == 0)
148 QFileInfo entryInfo(path);
149 if (entryInfo.isExecutable() || entryInfo.ownerId() == 0) {
150 return true;
151 }
152
153 qCInfo(KCONFIG_CORE_LOG) << "Access to" << path << "denied, not owned by root and executable flag not set.";
154 return false;
155}
156
158{
159 Q_D(const KDesktopFile);
160 return d->desktopGroup.readEntry("Type", QString());
161}
162
164{
165 Q_D(const KDesktopFile);
166 return d->desktopGroup.readEntry("Icon", QString());
167}
168
170{
171 Q_D(const KDesktopFile);
172 return d->desktopGroup.readEntry("Name", QString());
173}
174
176{
177 Q_D(const KDesktopFile);
178 return d->desktopGroup.readEntry("Comment", QString());
179}
180
182{
183 Q_D(const KDesktopFile);
184 return d->desktopGroup.readEntry("GenericName", QString());
185}
186
188{
189 Q_D(const KDesktopFile);
190 // NOT readPathEntry, it is not XDG-compliant: it performs
191 // various expansions, like $HOME. Note that the expansion
192 // behaviour still happens if the "e" flag is set, maintaining
193 // backwards compatibility.
194 return d->desktopGroup.readEntry("Path", QString());
195}
196
198{
199 Q_D(const KDesktopFile);
200 if (hasDeviceType()) {
201 return d->desktopGroup.readEntry("MountPoint", QString());
202 } else {
203 // NOT readPathEntry (see readPath())
204 QString url = d->desktopGroup.readEntry("URL", QString());
205 if (!url.isEmpty() && !QDir::isRelativePath(url)) {
206 // Handle absolute paths as such (i.e. we need to escape them)
207 return QUrl::fromLocalFile(url).toString();
208 }
209 return url;
210 }
211}
212
214{
215 Q_D(const KDesktopFile);
216 return d->desktopGroup.readXdgListEntry("Actions");
217}
218
220{
221 Q_D(const KDesktopFile);
222 return d->desktopGroup.readXdgListEntry("MimeType");
223}
224
226{
227 return KConfigGroup(this, QLatin1String("Desktop Action ") + group);
228}
229
231{
232 return const_cast<KDesktopFile *>(this)->actionGroup(group);
233}
234
235bool KDesktopFile::hasActionGroup(const QString &group) const
236{
237 return hasGroup(QString(QLatin1String("Desktop Action ") + group));
238}
239
241{
242 return readType() == QLatin1String("Link");
243}
244
246{
247 return readType() == QLatin1String("Application");
248}
249
251{
252 return readType() == QLatin1String("FSDevice");
253}
254
256{
257 Q_D(const KDesktopFile);
258 // Test for TryExec and "X-KDE-AuthorizeAction"
259 // NOT readPathEntry (see readPath())
260 const QString te = d->desktopGroup.readEntry("TryExec", QString());
262 return false;
263 }
264 const QStringList list = d->desktopGroup.readEntry("X-KDE-AuthorizeAction", QStringList());
265 const auto isNotAuthorized = std::any_of(list.cbegin(), list.cend(), [](const QString &action) {
266 return !KAuthorized::authorize(action.trimmed());
267 });
268 if (isNotAuthorized) {
269 return false;
270 }
271
272 // See also KService::username()
273 if (const bool su = d->desktopGroup.readEntry("X-KDE-SubstituteUID", false)) {
274 QString user = d->desktopGroup.readEntry("X-KDE-Username", QString());
275 if (user.isEmpty()) {
276 user = qEnvironmentVariable("ADMIN_ACCOUNT"), QStringLiteral("root");
277 }
278 if (!KAuthorized::authorize(QLatin1String("user/") + user)) {
279 return false;
280 }
281 }
282
283 return true;
284}
285
287{
288 Q_D(const KDesktopFile);
289 return d->desktopGroup.readPathEntry("X-DocPath", QString());
290}
291
293{
294 KDesktopFile *config = new KDesktopFile(QString());
295 this->KConfig::copyTo(file, config);
296 return config;
297}
298
300{
301 return name();
302}
303
305{
306 Q_D(const KDesktopFile);
307 return d->desktopGroup.readEntry("NoDisplay", false);
308}
309
311{
312 QList<KDesktopFileAction> desktopFileActions;
313 const QStringList actionKeys = readActions();
314 for (const QString &actionKey : actionKeys) {
315 const KConfigGroup grp = actionGroup(actionKey);
316 desktopFileActions << KDesktopFileAction(actionKey, grp.readEntry("Name"), grp.readEntry("Icon"), grp.readEntry("Exec"), fileName());
317 }
318 return desktopFileActions;
319}
static Q_INVOKABLE bool authorize(const QString &action)
Returns whether the user is permitted to perform a certain action.
bool hasGroup(const QString &group) const
Returns true if the specified group is known about.
KConfigGroup group(const QString &group)
Returns an object for the named subgroup.
A class for one specific group in a KConfig object.
T readEntry(const QString &key, const T &aDefault) const
Reads the value of an entry specified by pKey in the current group.
The central class of the KDE configuration data system.
Definition kconfig.h:56
void reparseConfiguration()
Updates the state of this object to match the persistent storage.
Definition kconfig.cpp:647
QString name() const
Returns the filename used to store the configuration.
Definition kconfig.cpp:560
KConfig * copyTo(const QString &file, KConfig *config=nullptr) const
Copies all entries from this config object to a new config object that will save itself to file.
Definition kconfig.cpp:542
Class for representing an Action of a desktop file.
KDE Desktop File Management.
bool hasApplicationType() const
Checks whether there is an entry "Type=Application".
QString readPath() const
Returns the value of the "Path=" entry.
QString fileName() const
Returns the name of the .desktop file that was used to construct this KDesktopFile.
KConfigGroup actionGroup(const QString &group)
Sets the desktop action group.
QString readGenericName() const
Returns the value of the "GenericName=" entry.
QStringList readMimeTypes() const
Returns a list of the "MimeType=" entries.
bool hasDeviceType() const
Checks whether there is an entry "Type=FSDevice".
QString readName() const
Returns the value of the "Name=" entry.
KDesktopFile * copyTo(const QString &file) const
Copies all entries from this config object to a new KDesktopFile object that will save itself to file...
bool noDisplay() const
Whether the entry should be suppressed in menus.
QString readComment() const
Returns the value of the "Comment=" entry.
QList< KDesktopFileAction > actions() const
KDesktopFile(QStandardPaths::StandardLocation resourceType, const QString &fileName)
Constructs a KDesktopFile object.
~KDesktopFile() override
Destructs the KDesktopFile object.
static bool isDesktopFile(const QString &path)
Checks whether this is really a desktop file.
bool hasLinkType() const
Checks whether there is a "Type=Link" entry.
bool tryExec() const
Checks whether the TryExec field contains a binary which is found on the local system.
KConfigGroup desktopGroup() const
Returns the main config group (named "Desktop Entry") in a .desktop file.
static QString locateLocal(const QString &path)
Returns the location where changes for the .desktop file path should be written to.
QString readDocPath() const
Returns the value of the "X-DocPath=" Or "DocPath=" entry.
QString readUrl() const
Returns the value of the "URL=" entry.
QString readIcon() const
Returns the value of the "Icon=" entry.
static bool isAuthorizedDesktopFile(const QString &path)
Checks whether the user is authorized to run this desktop file.
bool hasActionGroup(const QString &group) const
Returns true if the action group exists, false otherwise.
QString readType() const
Returns the value of the "Type=" entry.
QStringList readActions() const
Returns a list of the "Actions=" entries.
QString path(const QString &relativePath)
bool isRelativePath(const QString &path)
QString canonicalFilePath() const const
const_iterator cbegin() const const
const_iterator cend() const const
const_reverse_iterator crbegin() const const
const_reverse_iterator crend() const const
QString findExecutable(const QString &executableName, const QStringList &paths)
QStringList standardLocations(StandardLocation type)
QString writableLocation(StandardLocation type)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
QString mid(qsizetype position, qsizetype n) const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QStringView mid(qsizetype start, qsizetype length) const const
CaseSensitivity
QUrl fromLocalFile(const QString &localFile)
QString toString(FormattingOptions options) const const
Q_D(Todo)
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jun 14 2024 11:57:17 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.