KConfig

kdesktopfile.cpp
1 /*
2  This file is part of the KDE libraries
3  SPDX-FileCopyrightText: 1999 Pietro Iglio <[email protected]>
4  SPDX-FileCopyrightText: 1999 Preston Brown <[email protected]>
5 
6  SPDX-License-Identifier: LGPL-2.0-or-later
7 */
8 
9 #include "kdesktopfile.h"
10 
11 #ifndef Q_OS_WIN
12 #include <unistd.h>
13 #endif
14 
15 #include <QDir>
16 #include <QFileInfo>
17 #include <QUrl>
18 #include <qstandardpaths.h>
19 
20 #include "kauthorized.h"
21 #include "kconfig_p.h"
22 #include "kconfiggroup.h"
23 #include "kconfigini_p.h"
24 #include "kconfig_core_log_settings.h"
25 
26 class KDesktopFilePrivate : public KConfigPrivate
27 {
28 public:
29  KDesktopFilePrivate(QStandardPaths::StandardLocation resourceType, const QString &fileName);
30  KConfigGroup desktopGroup;
31 };
32 
33 KDesktopFilePrivate::KDesktopFilePrivate(QStandardPaths::StandardLocation resourceType, const QString &fileName)
34  : KConfigPrivate(KConfig::NoGlobals, resourceType)
35 {
36  mBackend = new KConfigIniBackend();
37  bDynamicBackend = false;
38  changeFileName(fileName);
39 }
40 
42  : KConfig(*new KDesktopFilePrivate(resourceType, fileName))
43 {
44  Q_D(KDesktopFile);
46  d->desktopGroup = KConfigGroup(this, "Desktop Entry");
47 }
48 
50  : KConfig(*new KDesktopFilePrivate(QStandardPaths::ApplicationsLocation, fileName))
51 {
52  Q_D(KDesktopFile);
54  d->desktopGroup = KConfigGroup(this, "Desktop Entry");
55 }
56 
58 {
59 }
60 
61 KConfigGroup KDesktopFile::desktopGroup() const
62 {
63  Q_D(const KDesktopFile);
64  return d->desktopGroup;
65 }
66 
68 {
69  QString relativePath;
70  QChar plus(QLatin1Char('/'));
71  // Relative to config? (e.g. for autostart)
73  for (const QString &dir : lstGenericConfigLocation) {
74  if (path.startsWith(dir + plus)) {
75  relativePath = path.mid(dir.length() + 1);
77  }
78  }
79  // Relative to xdg data dir? (much more common)
81  for (const QString &dir : lstGenericDataLocation) {
82  if (path.startsWith(dir + plus)) {
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(QLatin1Char('/')) + 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  const Qt::CaseSensitivity sensitivity = Qt::CaseSensitive;
115 #else
116  const Qt::CaseSensitivity sensitivity = Qt::CaseInsensitive;
117 #endif
118 
119  // Check if the .desktop file is installed as part of KDE or XDG.
121  for (const QString &prefix : appsDirs) {
122  if (QDir(prefix).exists() && realPath.startsWith(QFileInfo(prefix).canonicalFilePath(), sensitivity)) {
123  return true;
124  }
125  }
126  const QString servicesDir = QStringLiteral("kservices5/"); // KGlobal::dirs()->xdgDataRelativePath("services")
128  for (const QString &xdgDataPrefix : lstGenericDataLocation) {
129  if (QDir(xdgDataPrefix).exists()) {
130  const QString prefix = QFileInfo(xdgDataPrefix).canonicalFilePath();
131  if (realPath.startsWith(prefix + QLatin1Char('/') + servicesDir, sensitivity)) {
132  return true;
133  }
134  }
135  }
136  const QString autostartDir = QStringLiteral("autostart/");
138  for (const QString &xdgDataPrefix : lstConfigPath) {
139  if (QDir(xdgDataPrefix).exists()) {
140  const QString prefix = QFileInfo(xdgDataPrefix).canonicalFilePath();
141  if (realPath.startsWith(prefix + QLatin1Char('/') + autostartDir, sensitivity)) {
142  return true;
143  }
144  }
145  }
146 
147  // Forbid desktop files outside of standard locations if kiosk is set so
148  if (!KAuthorized::authorize(QStringLiteral("run_desktop_files"))) {
149  qCWarning(KCONFIG_CORE_LOG) << "Access to '" << path << "' denied because of 'run_desktop_files' restriction.";
150  return false;
151  }
152 
153  // Not otherwise permitted, so only allow if the file is executable, or if
154  // owned by root (uid == 0)
155  QFileInfo entryInfo(path);
156  if (entryInfo.isExecutable() || entryInfo.ownerId() == 0) {
157  return true;
158  }
159 
160  qCWarning(KCONFIG_CORE_LOG) << "Access to '" << path << "' denied, not owned by root, executable flag not set.";
161  return false;
162 }
163 
165 {
166  Q_D(const KDesktopFile);
167  return d->desktopGroup.readEntry("Type", QString());
168 }
169 
171 {
172  Q_D(const KDesktopFile);
173  return d->desktopGroup.readEntry("Icon", QString());
174 }
175 
177 {
178  Q_D(const KDesktopFile);
179  return d->desktopGroup.readEntry("Name", QString());
180 }
181 
183 {
184  Q_D(const KDesktopFile);
185  return d->desktopGroup.readEntry("Comment", QString());
186 }
187 
189 {
190  Q_D(const KDesktopFile);
191  return d->desktopGroup.readEntry("GenericName", QString());
192 }
193 
195 {
196  Q_D(const KDesktopFile);
197  // NOT readPathEntry, it is not XDG-compliant: it performs
198  // various expansions, like $HOME. Note that the expansion
199  // behaviour still happens if the "e" flag is set, maintaining
200  // backwards compatibility.
201  return d->desktopGroup.readEntry("Path", QString());
202 }
203 
205 {
206  Q_D(const KDesktopFile);
207  return d->desktopGroup.readEntry("Dev", QString());
208 }
209 
211 {
212  Q_D(const KDesktopFile);
213  if (hasDeviceType()) {
214  return d->desktopGroup.readEntry("MountPoint", QString());
215  } else {
216  // NOT readPathEntry (see readPath())
217  QString url = d->desktopGroup.readEntry("URL", QString());
218  if (!url.isEmpty() && !QDir::isRelativePath(url)) {
219  // Handle absolute paths as such (i.e. we need to escape them)
220  return QUrl::fromLocalFile(url).toString();
221  }
222  return url;
223  }
224 }
225 
227 {
228  Q_D(const KDesktopFile);
229  return d->desktopGroup.readXdgListEntry("Actions");
230 }
231 
233 {
234  Q_D(const KDesktopFile);
235  return d->desktopGroup.readXdgListEntry("MimeType");
236 }
237 
239 {
240  return KConfigGroup(this, QLatin1String("Desktop Action ") + group);
241 }
242 
244 {
245  return const_cast<KDesktopFile *>(this)->actionGroup(group);
246 }
247 
248 bool KDesktopFile::hasActionGroup(const QString &group) const
249 {
250  return hasGroup(QString(QLatin1String("Desktop Action ") + group).toUtf8().constData());
251 }
252 
254 {
255  return readType() == QLatin1String("Link");
256 }
257 
259 {
260  return readType() == QLatin1String("Application");
261 }
262 
264 {
265  return readType() == QLatin1String("FSDevice");
266 }
267 
269 {
270  Q_D(const KDesktopFile);
271  // Test for TryExec and "X-KDE-AuthorizeAction"
272  // NOT readPathEntry (see readPath())
273  QString te = d->desktopGroup.readEntry("TryExec", QString());
274 
275  if (!te.isEmpty()) {
277  return false;
278  }
279  }
280  const QStringList list = d->desktopGroup.readEntry("X-KDE-AuthorizeAction", QStringList());
281 
282  if (!list.isEmpty()) {
283  for (QStringList::ConstIterator it = list.begin();
284  it != list.end();
285  ++it) {
286  if (!KAuthorized::authorize((*it).trimmed())) {
287  return false;
288  }
289  }
290  }
291 
292  // See also KService::username()
293  bool su = d->desktopGroup.readEntry("X-KDE-SubstituteUID", false);
294  if (su) {
295  QString user = d->desktopGroup.readEntry("X-KDE-Username", QString());
296  if (user.isEmpty()) {
297  user = QString::fromLocal8Bit(qgetenv("ADMIN_ACCOUNT"));
298  }
299  if (user.isEmpty()) {
300  user = QStringLiteral("root");
301  }
302  if (!KAuthorized::authorize(QLatin1String("user/") + user)) {
303  return false;
304  }
305  }
306 
307  return true;
308 }
309 
313 //QString KDesktopFile::fileName() const { return backEnd->fileName(); }
314 
318 //QString
319 //KDesktopFile::resource() const { return backEnd->resource(); }
320 
321 #if KCONFIGCORE_BUILD_DEPRECATED_SINCE(5, 42)
324 {
325  Q_D(const KDesktopFile);
326  return d->desktopGroup.readXdgListEntry("SortOrder");
327 }
328 #endif
329 
330 //void KDesktopFile::virtual_hook( int id, void* data )
331 //{ KConfig::virtual_hook( id, data ); }
332 
334 {
335  Q_D(const KDesktopFile);
336  return d->desktopGroup.readPathEntry("X-DocPath", QString());
337 }
338 
340 {
341  KDesktopFile *config = new KDesktopFile(QString());
342  this->KConfig::copyTo(file, config);
343 // config->setDesktopGroup();
344  return config;
345 }
346 
347 QStandardPaths::StandardLocation KDesktopFile::resource() const
348 {
349  Q_D(const KDesktopFile);
350  return d->resourceType;
351 }
352 
353 QString KDesktopFile::fileName() const
354 {
355  return name();
356 }
357 
359 {
360  Q_D(const KDesktopFile);
361  if (d->desktopGroup.readEntry("NoDisplay", false)) {
362  return true;
363  }
364  if (d->desktopGroup.hasKey("OnlyShowIn")) {
365  if (!d->desktopGroup.readXdgListEntry("OnlyShowIn").contains(QLatin1String("KDE"))) {
366  return true;
367  }
368  }
369  if (d->desktopGroup.hasKey("NotShowIn")) {
370  if (d->desktopGroup.readXdgListEntry("NotShowIn").contains(QLatin1String("KDE"))) {
371  return true;
372  }
373  }
374  return false;
375 }
bool tryExec() const
Checks whether the TryExec field contains a binary which is found on the local system.
QString writableLocation(QStandardPaths::StandardLocation type)
QString name() const
Returns the filename used to store the configuration.
Definition: kconfig.cpp:548
QString readComment() const
Returns the value of the "Comment=" entry.
QString findExecutable(const QString &executableName, const QStringList &paths)
bool hasGroup(const QString &group) const
Returns true if the specified group is known about.
Definition: kconfigbase.cpp:16
KConfigGroup group(const QByteArray &group)
Returns an object for the named subgroup.
Definition: kconfigbase.cpp:31
bool hasApplicationType() const
Checks whether there is an entry "Type=Application".
QString toString(QUrl::FormattingOptions options) const const
QStringList sortOrder() const
Returns the entry of the "SortOrder=" entry.
bool noDisplay() const
Whether the entry should be suppressed in menus.
QStringList standardLocations(QStandardPaths::StandardLocation type)
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
static bool isAuthorizedDesktopFile(const QString &path)
Checks whether the user is authorized to run this desktop file.
QString readType() const
Returns the value of the "Type=" entry.
QString canonicalFilePath() const const
QString fromLocal8Bit(const char *str, int size)
QString readDevice() const
Returns the value of the "Dev=" entry.
bool hasDeviceType() const
Checks whether there is an entry "Type=FSDevice".
KDesktopFile * copyTo(const QString &file) const
Copies all entries from this config object to a new KDesktopFile object that will save itself to file...
CaseSensitivity
bool isEmpty() const const
bool isEmpty() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString readUrl() const
Returns the value of the "URL=" entry.
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:529
bool hasLinkType() const
Checks whether there is a "Type=Link" entry.
QList::iterator end()
KDesktopFile(QStandardPaths::StandardLocation resourceType, const QString &fileName)
Constructs a KDesktopFile object.
QStringList readActions() const
Returns a list of the "Actions=" entries.
bool isRelativePath(const QString &path)
KDE Desktop File Management.
Definition: kdesktopfile.h:26
A class for one specific group in a KConfig object.
Definition: kconfiggroup.h:38
QString readGenericName() const
Returns the value of the "GenericName=" entry.
The central class of the KDE configuration data system.
Definition: kconfig.h:56
virtual ~KDesktopFile()
Destructs the KDesktopFile object.
QString mid(int position, int n) const const
static bool isDesktopFile(const QString &path)
Checks whether this is really a desktop file.
QStringList readMimeTypes() const
Returns a list of the "MimeType=" entries.
static QString locateLocal(const QString &path)
Returns the location where changes for the .desktop file path should be written to.
void reparseConfiguration()
Updates the state of this object to match the persistent storage.
Definition: kconfig.cpp:637
KCONFIGCORE_EXPORT bool authorize(const QString &action)
Returns whether the user is permitted to perform a certain action.
typedef ConstIterator
uint ownerId() const const
int length() const const
bool hasActionGroup(const QString &group) const
Returns true if the action group exists, false otherwise.
QString readIcon() const
Returns the value of the "Icon=" entry.
KConfigGroup actionGroup(const QString &group)
Sets the desktop action group.
QString readPath() const
Returns the value of the "Path=" entry.
QString readDocPath() const
Returns the value of the "X-DocPath=" Or "DocPath=" entry.
QList::iterator begin()
QString readName() const
Returns the value of the "Name=" entry.
bool isExecutable() const const
QUrl fromLocalFile(const QString &localFile)
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Fri Jul 3 2020 22:47:12 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.