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 // make sure the [Desktop Entry] group is always the first one, as required by the spec
38 mBackend.setPrimaryGroup(QStringLiteral("Desktop Entry"));
39 }
40 KConfigGroup desktopGroup;
41};
42
44 : KConfig(*new KDesktopFilePrivate(resourceType, fileName))
45{
48 d->desktopGroup = KConfigGroup(this, QStringLiteral("Desktop Entry"));
49}
50
55
57
58KConfigGroup KDesktopFile::desktopGroup() const
59{
60 Q_D(const KDesktopFile);
61 return d->desktopGroup;
62}
63
65{
66 static const QLatin1Char slash('/');
67
68 // Relative to config? (e.g. for autostart)
70 // Iterate from the last item since some items may be subfolders of others.
71 auto it = std::find_if(genericConfig.crbegin(), genericConfig.crend(), [&path](const QString &dir) {
72 return path.startsWith(dir + slash);
73 });
74 if (it != genericConfig.crend()) {
76 }
77
78 QString relativePath;
79 // Relative to xdg data dir? (much more common)
81 for (const QString &dir : lstGenericDataLocation) {
82 if (path.startsWith(dir + slash)) {
83 relativePath = path.mid(dir.length() + 1);
84 }
85 }
86 if (relativePath.isEmpty()) {
87 // What now? The desktop file doesn't come from XDG_DATA_DIRS. Use filename only and hope for the best.
88 relativePath = path.mid(path.lastIndexOf(slash) + 1);
89 }
91}
92
94{
95 return path.endsWith(QLatin1String(".desktop"));
96}
97
99{
100 if (path.isEmpty()) {
101 return false; // Empty paths are not ok.
102 }
103
104 if (QDir::isRelativePath(path)) {
105 return true; // Relative paths are ok.
106 }
107
108 const QString realPath = QFileInfo(path).canonicalFilePath();
109 if (realPath.isEmpty()) {
110 return false; // File doesn't exist.
111 }
112
113#ifndef Q_OS_WIN
114 static constexpr Qt::CaseSensitivity sensitivity = Qt::CaseSensitive;
115#else
116 static constexpr Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
117#endif
118
119 // Check if the .desktop file is installed as part of KDE or XDG.
121 auto it = std::find_if(appsDirs.cbegin(), appsDirs.cend(), [&realPath, &path](const QString &prefix) {
122 QFileInfo info(prefix);
123 return info.exists() && info.isDir() && (realPath.startsWith(info.canonicalFilePath(), sensitivity) || path.startsWith(info.canonicalFilePath()));
124 });
125 if (it != appsDirs.cend()) {
126 return true;
127 }
128
129 const QString autostartDir = QStringLiteral("autostart/");
131 auto configIt = std::find_if(lstConfigPath.cbegin(), lstConfigPath.cend(), [&realPath, &autostartDir](const QString &xdgDataPrefix) {
132 QFileInfo info(xdgDataPrefix);
133 if (info.exists() && info.isDir()) {
134 const QString prefix = info.canonicalFilePath();
135 return realPath.startsWith(prefix + QLatin1Char('/') + autostartDir, sensitivity);
136 }
137 return false;
138 });
139 if (configIt != lstConfigPath.cend()) {
140 return true;
141 }
142
143 // Forbid desktop files outside of standard locations if kiosk is set so
144 if (!KAuthorized::authorize(QStringLiteral("run_desktop_files"))) {
145 qCWarning(KCONFIG_CORE_LOG) << "Access to" << path << "denied because of 'run_desktop_files' restriction.";
146 return false;
147 }
148
149 // Not otherwise permitted, so only allow if the file is executable, or if
150 // owned by root (uid == 0)
151 QFileInfo entryInfo(path);
152 if (entryInfo.isExecutable() || entryInfo.ownerId() == 0) {
153 return true;
154 }
155
156 qCInfo(KCONFIG_CORE_LOG) << "Access to" << path << "denied, not owned by root and executable flag not set.";
157 return false;
158}
159
161{
162 Q_D(const KDesktopFile);
163 return d->desktopGroup.readEntry("Type", QString());
164}
165
167{
168 Q_D(const KDesktopFile);
169 return d->desktopGroup.readEntry("Icon", QString());
170}
171
173{
174 Q_D(const KDesktopFile);
175 return d->desktopGroup.readEntry("Name", QString());
176}
177
179{
180 Q_D(const KDesktopFile);
181 return d->desktopGroup.readEntry("Comment", QString());
182}
183
185{
186 Q_D(const KDesktopFile);
187 return d->desktopGroup.readEntry("GenericName", QString());
188}
189
191{
192 Q_D(const KDesktopFile);
193 // NOT readPathEntry, it is not XDG-compliant: it performs
194 // various expansions, like $HOME. Note that the expansion
195 // behaviour still happens if the "e" flag is set, maintaining
196 // backwards compatibility.
197 return d->desktopGroup.readEntry("Path", QString());
198}
199
201{
202 Q_D(const KDesktopFile);
203 if (hasDeviceType()) {
204 return d->desktopGroup.readEntry("MountPoint", QString());
205 } else {
206 // NOT readPathEntry (see readPath())
207 QString url = d->desktopGroup.readEntry("URL", QString());
208 if (!url.isEmpty() && !QDir::isRelativePath(url)) {
209 // Handle absolute paths as such (i.e. we need to escape them)
210 return QUrl::fromLocalFile(url).toString();
211 }
212 return url;
213 }
214}
215
217{
218 Q_D(const KDesktopFile);
219 return d->desktopGroup.readXdgListEntry("Actions");
220}
221
223{
224 Q_D(const KDesktopFile);
225 return d->desktopGroup.readXdgListEntry("MimeType");
226}
227
229{
230 return KConfigGroup(this, QLatin1String("Desktop Action ") + group);
231}
232
234{
235 return const_cast<KDesktopFile *>(this)->actionGroup(group);
236}
237
239{
240 return hasGroup(QString(QLatin1String("Desktop Action ") + group));
241}
242
244{
245 return readType() == QLatin1String("Link");
246}
247
249{
250 return readType() == QLatin1String("Application");
251}
252
254{
255 return readType() == QLatin1String("FSDevice");
256}
257
259{
260 Q_D(const KDesktopFile);
261 // Test for TryExec and "X-KDE-AuthorizeAction"
262 // NOT readPathEntry (see readPath())
263 const QString te = d->desktopGroup.readEntry("TryExec", QString());
264 if (!te.isEmpty() && QStandardPaths::findExecutable(te).isEmpty()) {
265 return false;
266 }
267 const QStringList list = d->desktopGroup.readEntry("X-KDE-AuthorizeAction", QStringList());
268 const auto isNotAuthorized = std::any_of(list.cbegin(), list.cend(), [](const QString &action) {
269 return !KAuthorized::authorize(action.trimmed());
270 });
271 if (isNotAuthorized) {
272 return false;
273 }
274
275 // See also KService::username()
276 if (d->desktopGroup.readEntry("X-KDE-SubstituteUID", false)) {
277 QString user = d->desktopGroup.readEntry("X-KDE-Username", QString());
278 if (user.isEmpty()) {
279 user = qEnvironmentVariable("ADMIN_ACCOUNT"), QStringLiteral("root");
280 }
281 if (!KAuthorized::authorize(QLatin1String("user/") + user)) {
282 return false;
283 }
284 }
285
286 return true;
287}
288
290{
291 Q_D(const KDesktopFile);
292 return d->desktopGroup.readPathEntry("X-DocPath", QString());
293}
294
296{
297 KDesktopFile *config = new KDesktopFile(QString());
298 this->KConfig::copyTo(file, config);
299 return config;
300}
301
303{
304 return name();
305}
306
308{
309 Q_D(const KDesktopFile);
310 return d->desktopGroup.readEntry("NoDisplay", false);
311}
312
314{
315 QList<KDesktopFileAction> desktopFileActions;
316 const QStringList actionKeys = readActions();
317 for (const QString &actionKey : actionKeys) {
318 const KConfigGroup grp = actionGroup(actionKey);
319 desktopFileActions << KDesktopFileAction(actionKey, grp.readEntry("Name"), grp.readEntry("Icon"), grp.readEntry("Exec"), fileName());
320 }
321 return desktopFileActions;
322}
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.
KConfig(const QString &file=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
Creates a KConfig object to manipulate a configuration file for the current application.
Definition kconfig.cpp:241
void reparseConfiguration()
Updates the state of this object to match the persistent storage.
Definition kconfig.cpp:649
QString name() const
Returns the filename used to store the configuration.
Definition kconfig.cpp:562
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:544
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-2025 The KDE developers.
Generated on Fri Mar 28 2025 11:52:18 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.