• Skip to content
  • Skip to link menu
Brand

API Documentation

  1. KDE API Reference
  2. The KDE Frameworks
  3. KIO
  • KDE Home
  • Contact Us

Quick Links

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • File List
  • Dependencies
  • Related Pages

Class Picker

About

Resource and network access abstraction

Maintainer
David Faure
Supported platforms
FreeBSD, Linux, MacOSX, Windows
Community
IRC: #kde-devel on Freenode
Mailing list: kde-frameworks-devel
Use with CMake
find_package(KF5KIO)
target_link_libraries(yourapp KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::KIONTLM)
Use with QMake
QT += KIOCore KIOFileWidgets KIOWidgets KNTLM 
Clone
git clone git://anongit.kde.org/kio.git
Browse source
KIO on cgit.kde.org

KIO

  • frameworks
  • frameworks
  • kio
  • src
  • widgets
krun.cpp
1 /* This file is part of the KDE libraries
2  Copyright (C) 2000 Torben Weis <weis@kde.org>
3  Copyright (C) 2006 David Faure <faure@kde.org>
4  Copyright (C) 2009 Michael Pyne <michael.pyne@kdemail.net>
5 
6  This library is free software; you can redistribute it and/or
7  modify it under the terms of the GNU Library General Public
8  License as published by the Free Software Foundation; either
9  version 2 of the License, or (at your option) any later version.
10 
11  This library is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14  Library General Public License for more details.
15 
16  You should have received a copy of the GNU Library General Public License
17  along with this library; see the file COPYING.LIB. If not, write to
18  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
19  Boston, MA 02110-1301, USA.
20 */
21 
22 #include "krun.h"
23 #include "krun_p.h"
24 #include <config-kiowidgets.h> // HAVE_X11
25 #include "kio_widgets_debug.h"
26 
27 #include <assert.h>
28 #include <string.h>
29 #include <typeinfo>
30 #include <qplatformdefs.h>
31 
32 #include <QDialog>
33 #include <QDialogButtonBox>
34 #include <QWidget>
35 #include <QLabel>
36 #include <QVBoxLayout>
37 #include <QHBoxLayout>
38 #include <QPlainTextEdit>
39 #include <QPushButton>
40 #include <QApplication>
41 #include <QDesktopWidget>
42 #include <qmimedatabase.h>
43 #include <QDebug>
44 #include <QDBusConnection>
45 #include <QDBusConnectionInterface>
46 #include <QDBusInterface>
47 #include <QDBusReply>
48 #include <QHostInfo>
49 
50 #include <kiconloader.h>
51 #include <kjobuidelegate.h>
52 #include <kmimetypetrader.h>
53 #include "kio/job.h"
54 #include "kio/global.h"
55 #include "kio/scheduler.h"
56 #include "kopenwithdialog.h"
57 #include "krecentdocument.h"
58 #include "kdesktopfileactions.h"
59 #include "executablefileopendialog_p.h"
60 #include <kio/desktopexecparser.h>
61 
62 #include <kurlauthorized.h>
63 #include <kmessagebox.h>
64 #include <ktoolinvocation.h>
65 #include <klocalizedstring.h>
66 #include <kprotocolmanager.h>
67 #include <kprocess.h>
68 #include <kiconloader.h>
69 #include <kjobwidgets.h>
70 #include <ksharedconfig.h>
71 
72 #include <QtCore/QFile>
73 #include <QtCore/QFileInfo>
74 #include <QtCore/QTextStream>
75 #include <QtCore/QDate>
76 #include <QtCore/QRegExp>
77 #include <QDir>
78 #include <kdesktopfile.h>
79 #include <kshell.h>
80 #include <kconfiggroup.h>
81 #include <kstandardguiitem.h>
82 #include <kguiitem.h>
83 #include <qsavefile.h>
84 
85 #if HAVE_X11
86 #include <kwindowsystem.h>
87 #elif defined(Q_OS_WIN)
88 #include <QDesktopServices>
89 #endif
90 #include <qplatformdefs.h>
91 #include <qstandardpaths.h>
92 
93 KRun::KRunPrivate::KRunPrivate(KRun *parent)
94  : q(parent),
95  m_showingDialog(false)
96 {
97 }
98 
99 void KRun::KRunPrivate::startTimer()
100 {
101  m_timer->start(0);
102 }
103 
104 // ---------------------------------------------------------------------------
105 
106 static QString schemeHandler(const QString &protocol)
107 {
108  // We have up to two sources of data, for protocols not handled by kioslaves (so called "helper") :
109  // 1) the exec line of the .protocol file, if there's one
110  // 2) the application associated with x-scheme-handler/<protocol> if there's one
111 
112  // If both exist, then:
113  // A) if the .protocol file says "launch an application", then the new-style handler-app has priority
114  // B) but if the .protocol file is for a kioslave (e.g. kio_http) then this has priority over
115  // firefox or chromium saying x-scheme-handler/http. Gnome people want to send all HTTP urls
116  // to a webbrowser, but we want mimetype-determination-in-calling-application by default
117  // (the user can configure a BrowserApplication though)
118 
119  const KService::Ptr service = KMimeTypeTrader::self()->preferredService(QLatin1String("x-scheme-handler/") + protocol);
120  if (service) {
121  return service->exec(); // for helper protocols, the handler app has priority over the hardcoded one (see A above)
122  }
123  Q_ASSERT(KProtocolInfo::isHelperProtocol(protocol));
124  return KProtocolInfo::exec(protocol);
125 }
126 
127 // ---------------------------------------------------------------------------
128 
129 bool KRun::isExecutableFile(const QUrl &url, const QString &mimetype)
130 {
131  if (!url.isLocalFile()) {
132  return false;
133  }
134  QFileInfo file(url.toLocalFile());
135  if (file.isExecutable()) { // Got a prospective file to run
136  QMimeDatabase db;
137  QMimeType mimeType = db.mimeTypeForName(mimetype);
138  if (mimeType.inherits(QStringLiteral("application/x-executable")) ||
139 #ifdef Q_OS_WIN
140  mimeType.inherits(QLatin1String("application/x-ms-dos-executable")) ||
141 #endif
142  mimeType.inherits(QStringLiteral("application/x-executable-script")) ||
143  mimeType.inherits(QStringLiteral("application/x-sharedlib"))
144  ) {
145  return true;
146  }
147  }
148  return false;
149 }
150 
151 void KRun::handleInitError(int kioErrorCode, const QString &errorMsg)
152 {
153  Q_UNUSED(kioErrorCode);
154  d->m_showingDialog = true;
155  KMessageBox::error(d->m_window, errorMsg);
156  d->m_showingDialog = false;
157 }
158 
159 void KRun::handleError(KJob *job)
160 {
161  Q_ASSERT(job);
162  if (job) {
163  d->m_showingDialog = true;
164  job->uiDelegate()->showErrorMessage();
165  d->m_showingDialog = false;
166  }
167 }
168 
169 #ifndef KIOWIDGETS_NO_DEPRECATED
170 bool KRun::runUrl(const QUrl &url, const QString &mimetype, QWidget *window, bool tempFile, bool runExecutables, const QString &suggestedFileName, const QByteArray &asn)
171 {
172  RunFlags flags = tempFile ? KRun::DeleteTemporaryFiles : RunFlags();
173  if (runExecutables) {
174  flags |= KRun::RunExecutables;
175  }
176 
177  return runUrl(url, mimetype, window, flags, suggestedFileName, asn);
178 }
179 #endif
180 
181 // This is called by foundMimeType, since it knows the mimetype of the URL
182 bool KRun::runUrl(const QUrl &u, const QString &_mimetype, QWidget *window, RunFlags flags, const QString &suggestedFileName, const QByteArray &asn)
183 {
184  const bool runExecutables = flags.testFlag(KRun::RunExecutables);
185  const bool tempFile = flags.testFlag(KRun::DeleteTemporaryFiles);
186  bool noRun = false;
187  bool noAuth = false;
188  if (_mimetype == QLatin1String("inode/directory-locked")) {
189  KMessageBox::error(window,
190  i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", u.toDisplayString().toHtmlEscaped()));
191  return false;
192  } else if (_mimetype == QLatin1String("application/x-desktop")) {
193  if (u.isLocalFile() && runExecutables) {
194  return KDesktopFileActions::runWithStartup(u, true, asn);
195  }
196  } else if (isExecutableFile(u, _mimetype)) {
197  if (u.isLocalFile() && runExecutables) {
198  if (KAuthorized::authorize(QStringLiteral("shell_access"))) {
199  return (KRun::runCommand(KShell::quoteArg(u.toLocalFile()), QString(), QString(),
200  window, asn, u.adjusted(QUrl::RemoveFilename).toLocalFile())); // just execute the url as a command
201  // ## TODO implement deleting the file if tempFile==true
202  } else {
203  noAuth = true;
204  }
205  } else if (_mimetype == QLatin1String("application/x-executable")) {
206  noRun = true;
207  }
208  } else if (isExecutable(_mimetype)) {
209  if (!runExecutables) {
210  noRun = true;
211  }
212 
213  if (!KAuthorized::authorize(QStringLiteral("shell_access"))) {
214  noAuth = true;
215  }
216  }
217 
218  if (noRun) {
219  KMessageBox::sorry(window,
220  i18n("<qt>The file <b>%1</b> is an executable program. "
221  "For safety it will not be started.</qt>", u.toDisplayString().toHtmlEscaped()));
222  return false;
223  }
224  if (noAuth) {
225  KMessageBox::error(window,
226  i18n("<qt>You do not have permission to run <b>%1</b>.</qt>", u.toDisplayString().toHtmlEscaped()));
227  return false;
228  }
229 
230  QList<QUrl> lst;
231  lst.append(u);
232 
233  KService::Ptr offer = KMimeTypeTrader::self()->preferredService(_mimetype);
234 
235  if (!offer) {
236 #ifdef Q_OS_WIN
237  // As KDE on windows doesnt know about the windows default applications offers will be empty in nearly all cases.
238  // So we use QDesktopServices::openUrl to let windows decide how to open the file
239  return QDesktopServices::openUrl(u);
240 #else
241  // Open-with dialog
242  // TODO : pass the mimetype as a parameter, to show it (comment field) in the dialog !
243  // Hmm, in fact KOpenWithDialog::setServiceType already guesses the mimetype from the first URL of the list...
244  return displayOpenWithDialog(lst, window, tempFile, suggestedFileName, asn);
245 #endif
246  }
247 
248  return KRun::runService(*offer, lst, window, tempFile, suggestedFileName, asn);
249 }
250 
251 bool KRun::displayOpenWithDialog(const QList<QUrl> &lst, QWidget *window, bool tempFiles,
252  const QString &suggestedFileName, const QByteArray &asn)
253 {
254  if (!KAuthorized::authorizeAction(QStringLiteral("openwith"))) {
255  KMessageBox::sorry(window,
256  i18n("You are not authorized to select an application to open this file."));
257  return false;
258  }
259 
260 #ifdef Q_OS_WIN
261  KConfigGroup cfgGroup(KSharedConfig::openConfig(), "KOpenWithDialog Settings");
262  if (cfgGroup.readEntry("Native", true)) {
263  return KRun::KRunPrivate::displayNativeOpenWithDialog(lst, window, tempFiles,
264  suggestedFileName, asn);
265  }
266 #endif
267  KOpenWithDialog dialog(lst, QString(), QString(), window);
268  dialog.setWindowModality(Qt::WindowModal);
269  if (dialog.exec()) {
270  KService::Ptr service = dialog.service();
271  if (!service) {
272  //qDebug() << "No service set, running " << dialog.text();
273  service = KService::Ptr(new KService(QString() /*name*/, dialog.text(), QString() /*icon*/));
274  }
275  return KRun::runService(*service, lst, window, tempFiles, suggestedFileName, asn);
276  }
277  return false;
278 }
279 
280 #ifndef KIOWIDGETS_NO_DEPRECATED
281 void KRun::shellQuote(QString &_str)
282 {
283  // Credits to Walter, says Bernd G. :)
284  if (_str.isEmpty()) { // Don't create an explicit empty parameter
285  return;
286  }
287  QChar q('\'');
288  _str.replace(q, QLatin1String("'\\''")).prepend(q).append(q);
289 }
290 #endif
291 
292 QStringList KRun::processDesktopExec(const KService &_service, const QList<QUrl> &_urls, bool tempFiles, const QString &suggestedFileName)
293 {
294  KIO::DesktopExecParser parser(_service, _urls);
295  parser.setUrlsAreTempFiles(tempFiles);
296  parser.setSuggestedFileName(suggestedFileName);
297  return parser.resultingArguments();
298 }
299 
300 #ifndef KIOWIDGETS_NO_DEPRECATED
301 QString KRun::binaryName(const QString &execLine, bool removePath)
302 {
303  return removePath ? KIO::DesktopExecParser::executableName(execLine) : KIO::DesktopExecParser::executablePath(execLine);
304 }
305 #endif
306 
307 static qint64 runCommandInternal(KProcess *proc, const KService *service, const QString &executable,
308  const QString &userVisibleName, const QString &iconName, QWidget *window,
309  const QByteArray &asn)
310 {
311  if (window) {
312  window = window->topLevelWidget();
313  }
314  if (service && !service->entryPath().isEmpty()
315  && !KDesktopFile::isAuthorizedDesktopFile(service->entryPath())) {
316  qCWarning(KIO_WIDGETS) << "No authorization to execute " << service->entryPath();
317  KMessageBox::sorry(window, i18n("You are not authorized to execute this file."));
318  delete proc;
319  return 0;
320  }
321 
322  QString bin = KIO::DesktopExecParser::executableName(executable);
323 #if HAVE_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
324  static bool isX11 = QGuiApplication::platformName() == QStringLiteral("xcb");
325  if (isX11) {
326  bool silent;
327  QByteArray wmclass;
328  KStartupInfoId id;
329  bool startup_notify = (asn != "0" && KRun::checkStartupNotify(QString() /*unused*/, service, &silent, &wmclass));
330  if (startup_notify) {
331  id.initId(asn);
332  id.setupStartupEnv();
333  KStartupInfoData data;
334  data.setHostname();
335  data.setBin(bin);
336  if (!userVisibleName.isEmpty()) {
337  data.setName(userVisibleName);
338  } else if (service && !service->name().isEmpty()) {
339  data.setName(service->name());
340  }
341  data.setDescription(i18n("Launching %1", data.name()));
342  if (!iconName.isEmpty()) {
343  data.setIcon(iconName);
344  } else if (service && !service->icon().isEmpty()) {
345  data.setIcon(service->icon());
346  }
347  if (!wmclass.isEmpty()) {
348  data.setWMClass(wmclass);
349  }
350  if (silent) {
351  data.setSilent(KStartupInfoData::Yes);
352  }
353  data.setDesktop(KWindowSystem::currentDesktop());
354  // QTBUG-59017 Calling winId() on an embedded widget will break interaction
355  // with it on high-dpi multi-screen setups (cf. also Bug 363548), hence using
356  // its parent window instead
357  if (window && window->window()) {
358  data.setLaunchedBy(window->window()->winId());
359  }
360  if (service && !service->entryPath().isEmpty()) {
361  data.setApplicationId(service->entryPath());
362  }
363  KStartupInfo::sendStartup(id, data);
364  }
365  qint64 pid = KProcessRunner::run(proc, executable, id);
366  if (startup_notify && pid) {
367  KStartupInfoData data;
368  data.addPid(pid);
369  KStartupInfo::sendChange(id, data);
370  KStartupInfo::resetStartupEnv();
371  }
372  return pid;
373  }
374 #else
375  Q_UNUSED(userVisibleName);
376  Q_UNUSED(iconName);
377 #endif
378  return KProcessRunner::run(proc, bin, KStartupInfoId());
379 }
380 
381 // This code is also used in klauncher.
382 bool KRun::checkStartupNotify(const QString & /*binName*/, const KService *service, bool *silent_arg, QByteArray *wmclass_arg)
383 {
384  bool silent = false;
385  QByteArray wmclass;
386  if (service && service->property(QStringLiteral("StartupNotify")).isValid()) {
387  silent = !service->property(QStringLiteral("StartupNotify")).toBool();
388  wmclass = service->property(QStringLiteral("StartupWMClass")).toString().toLatin1();
389  } else if (service && service->property(QStringLiteral("X-KDE-StartupNotify")).isValid()) {
390  silent = !service->property(QStringLiteral("X-KDE-StartupNotify")).toBool();
391  wmclass = service->property(QStringLiteral("X-KDE-WMClass")).toString().toLatin1();
392  } else { // non-compliant app
393  if (service) {
394  if (service->isApplication()) { // doesn't have .desktop entries needed, start as non-compliant
395  wmclass = "0"; // krazy:exclude=doublequote_chars
396  } else {
397  return false; // no startup notification at all
398  }
399  } else {
400 #if 0
401  // Create startup notification even for apps for which there shouldn't be any,
402  // just without any visual feedback. This will ensure they'll be positioned on the proper
403  // virtual desktop, and will get user timestamp from the ASN ID.
404  wmclass = '0';
405  silent = true;
406 #else // That unfortunately doesn't work, when the launched non-compliant application
407  // launches another one that is compliant and there is any delay inbetween (bnc:#343359)
408  return false;
409 #endif
410  }
411  }
412  if (silent_arg) {
413  *silent_arg = silent;
414  }
415  if (wmclass_arg) {
416  *wmclass_arg = wmclass;
417  }
418  return true;
419 }
420 
421 static qint64 runApplicationImpl(const KService &_service, const QList<QUrl> &_urls, QWidget *window,
422  KRun::RunFlags flags, const QString &suggestedFileName, const QByteArray &asn)
423 {
424  QList<QUrl> urlsToRun = _urls;
425  if ((_urls.count() > 1) && !_service.allowMultipleFiles()) {
426  // We need to launch the application N times. That sucks.
427  // We ignore the result for application 2 to N.
428  // For the first file we launch the application in the
429  // usual way. The reported result is based on this
430  // application.
431  QList<QUrl>::ConstIterator it = _urls.begin();
432  while (++it != _urls.end()) {
433  QList<QUrl> singleUrl;
434  singleUrl.append(*it);
435  runApplicationImpl(_service, singleUrl, window, flags, suggestedFileName, QByteArray());
436  }
437  urlsToRun.clear();
438  urlsToRun.append(_urls.first());
439  }
440  KIO::DesktopExecParser execParser(_service, urlsToRun);
441  execParser.setUrlsAreTempFiles(flags & KRun::DeleteTemporaryFiles);
442  execParser.setSuggestedFileName(suggestedFileName);
443  const QStringList args = execParser.resultingArguments();
444  if (args.isEmpty()) {
445  KMessageBox::sorry(window, i18n("Error processing Exec field in %1", _service.entryPath()));
446  return 0;
447  }
448  //qDebug() << "runTempService: KProcess args=" << args;
449 
450  KProcess * proc = new KProcess;
451  *proc << args;
452 
453  enum DiscreteGpuCheck { NotChecked, Present, Absent };
454  static DiscreteGpuCheck s_gpuCheck = NotChecked;
455 
456  if (_service.runOnDiscreteGpu() && s_gpuCheck == NotChecked) {
457  // Check whether we have a discrete gpu
458  bool hasDiscreteGpu = false;
459  QDBusInterface iface(QLatin1String("org.kde.Solid.PowerManagement"),
460  QLatin1String("/org/kde/Solid/PowerManagement"),
461  QLatin1String("org.kde.Solid.PowerManagement"),
462  QDBusConnection::sessionBus());
463  if (iface.isValid()) {
464  QDBusReply<bool> reply = iface.call(QLatin1String("hasDualGpu"));
465  if (reply.isValid()) {
466  hasDiscreteGpu = reply.value();
467  }
468  }
469 
470  s_gpuCheck = hasDiscreteGpu ? Present : Absent;
471  }
472 
473  if (_service.runOnDiscreteGpu() && s_gpuCheck == Present) {
474  proc->setEnv(QLatin1String("DRI_PRIME"), QLatin1String("1"));
475  }
476 
477  QString path(_service.path());
478  if (path.isEmpty() && !_urls.isEmpty() && _urls.first().isLocalFile()) {
479  path = _urls.first().adjusted(QUrl::RemoveFilename).toLocalFile();
480  }
481 
482  proc->setWorkingDirectory(path);
483 
484  return runCommandInternal(proc, &_service, KIO::DesktopExecParser::executablePath(_service.exec()),
485  _service.name(), _service.icon(), window, asn);
486 }
487 
488 // WARNING: don't call this from DesktopExecParser, since klauncher uses that too...
489 // TODO: make this async, see the job->exec() in there...
490 static QList<QUrl> resolveURLs(const QList<QUrl> &_urls, const KService &_service)
491 {
492  // Check which protocols the application supports.
493  // This can be a list of actual protocol names, or just KIO for KDE apps.
494  QStringList appSupportedProtocols = KIO::DesktopExecParser::supportedProtocols(_service);
495  QList<QUrl> urls(_urls);
496  if (!appSupportedProtocols.contains(QStringLiteral("KIO"))) {
497  for (QList<QUrl>::Iterator it = urls.begin(); it != urls.end(); ++it) {
498  const QUrl url = *it;
499  bool supported = KIO::DesktopExecParser::isProtocolInSupportedList(url, appSupportedProtocols);
500  //qDebug() << "Looking at url=" << url << " supported=" << supported;
501  if (!supported && KProtocolInfo::protocolClass(url.scheme()) == QLatin1String(":local")) {
502  // Maybe we can resolve to a local URL?
503  KIO::StatJob *job = KIO::mostLocalUrl(url);
504  if (job->exec()) { // ## nasty nested event loop!
505  const QUrl localURL = job->mostLocalUrl();
506  if (localURL != url) {
507  *it = localURL;
508  //qDebug() << "Changed to" << localURL;
509  }
510  }
511  }
512  }
513  }
514  return urls;
515 }
516 
517 // Simple QDialog that resizes the given text edit after being shown to more
518 // or less fit the enclosed text.
519 class SecureMessageDialog : public QDialog
520 {
521  Q_OBJECT
522 public:
523  SecureMessageDialog(QWidget *parent) : QDialog(parent), m_textEdit(nullptr)
524  {
525  }
526 
527  void setTextEdit(QPlainTextEdit *textEdit)
528  {
529  m_textEdit = textEdit;
530  }
531 
532 protected:
533  void showEvent(QShowEvent *e) Q_DECL_OVERRIDE
534  {
535  // Now that we're shown, use our width to calculate a good
536  // bounding box for the text, and resize m_textEdit appropriately.
537  QDialog::showEvent(e);
538 
539  if (!m_textEdit) {
540  return;
541  }
542 
543  QSize fudge(20, 24); // About what it sounds like :-/
544 
545  // Form rect with a lot of height for bounding. Use no more than
546  // 5 lines.
547  QRect curRect(m_textEdit->rect());
548  QFontMetrics metrics(fontMetrics());
549  curRect.setHeight(5 * metrics.lineSpacing());
550  curRect.setWidth(qMax(curRect.width(), 300)); // At least 300 pixels ok?
551 
552  QString text(m_textEdit->toPlainText());
553  curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
554 
555  // Scroll bars interfere. If we don't think there's enough room, enable
556  // the vertical scrollbar however.
557  m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
558  if (curRect.height() < m_textEdit->height()) { // then we've got room
559  m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
560  m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
561  }
562 
563  m_textEdit->setMinimumSize(curRect.size() + fudge);
564  m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
565  updateGeometry();
566  }
567 
568 private:
569  QPlainTextEdit *m_textEdit;
570 };
571 
572 // Helper function to make the given .desktop file executable by ensuring
573 // that a #!/usr/bin/env xdg-open line is added if necessary and the file has
574 // the +x bit set for the user. Returns false if either fails.
575 static bool makeFileExecutable(const QString &fileName)
576 {
577  // Open the file and read the first two characters, check if it's
578  // #!. If not, create a new file, prepend appropriate lines, and copy
579  // over.
580  QFile desktopFile(fileName);
581  if (!desktopFile.open(QFile::ReadOnly)) {
582  qCWarning(KIO_WIDGETS) << "Error opening service" << fileName << desktopFile.errorString();
583  return false;
584  }
585 
586  QByteArray header = desktopFile.peek(2); // First two chars of file
587  if (header.size() == 0) {
588  qCWarning(KIO_WIDGETS) << "Error inspecting service" << fileName << desktopFile.errorString();
589  return false; // Some kind of error
590  }
591 
592  if (header != "#!") {
593  // Add header
594  QSaveFile saveFile;
595  saveFile.setFileName(fileName);
596  if (!saveFile.open(QIODevice::WriteOnly)) {
597  qCWarning(KIO_WIDGETS) << "Unable to open replacement file for" << fileName << saveFile.errorString();
598  return false;
599  }
600 
601  QByteArray shebang("#!/usr/bin/env xdg-open\n");
602  if (saveFile.write(shebang) != shebang.size()) {
603  qCWarning(KIO_WIDGETS) << "Error occurred adding header for" << fileName << saveFile.errorString();
604  saveFile.cancelWriting();
605  return false;
606  }
607 
608  // Now copy the one into the other and then close and reopen desktopFile
609  QByteArray desktopData(desktopFile.readAll());
610  if (desktopData.isEmpty()) {
611  qCWarning(KIO_WIDGETS) << "Unable to read service" << fileName << desktopFile.errorString();
612  saveFile.cancelWriting();
613  return false;
614  }
615 
616  if (saveFile.write(desktopData) != desktopData.size()) {
617  qCWarning(KIO_WIDGETS) << "Error copying service" << fileName << saveFile.errorString();
618  saveFile.cancelWriting();
619  return false;
620  }
621 
622  desktopFile.close();
623  if (!saveFile.commit()) { // Figures....
624  qCWarning(KIO_WIDGETS) << "Error committing changes to service" << fileName << saveFile.errorString();
625  return false;
626  }
627 
628  if (!desktopFile.open(QFile::ReadOnly)) {
629  qCWarning(KIO_WIDGETS) << "Error re-opening service" << fileName << desktopFile.errorString();
630  return false;
631  }
632  } // Add header
633 
634  // corresponds to owner on unix, which will have to do since if the user
635  // isn't the owner we can't change perms anyways.
636  if (!desktopFile.setPermissions(QFile::ExeUser | desktopFile.permissions())) {
637  qCWarning(KIO_WIDGETS) << "Unable to change permissions for" << fileName << desktopFile.errorString();
638  return false;
639  }
640 
641  // whew
642  return true;
643 }
644 
645 // Helper function to make a .desktop file executable if prompted by the user.
646 // returns true if KRun::run() should continue with execution, false if user declined
647 // to make the file executable or we failed to make it executable.
648 static bool makeServiceExecutable(const KService &service, QWidget *window)
649 {
650  if (!KAuthorized::authorize(QStringLiteral("run_desktop_files"))) {
651  qCWarning(KIO_WIDGETS) << "No authorization to execute " << service.entryPath();
652  KMessageBox::sorry(window, i18n("You are not authorized to execute this service."));
653  return false; // Don't circumvent the Kiosk
654  }
655 
656  SecureMessageDialog *baseDialog = new SecureMessageDialog(window);
657  baseDialog->setWindowTitle(i18nc("Warning about executing unknown .desktop file", "Warning"));
658 
659  QVBoxLayout *topLayout = new QVBoxLayout;
660  baseDialog->setLayout(topLayout);
661 
662  // Dialog will have explanatory text with a disabled lineedit with the
663  // Exec= to make it visually distinct.
664  QWidget *baseWidget = new QWidget(baseDialog);
665  QHBoxLayout *mainLayout = new QHBoxLayout(baseWidget);
666 
667  QLabel *iconLabel = new QLabel(baseWidget);
668  QPixmap warningIcon(KIconLoader::global()->loadIcon(QStringLiteral("dialog-warning"), KIconLoader::NoGroup, KIconLoader::SizeHuge));
669  mainLayout->addWidget(iconLabel);
670  iconLabel->setPixmap(warningIcon);
671 
672  QVBoxLayout *contentLayout = new QVBoxLayout;
673  QString warningMessage = i18nc("program name follows in a line edit below",
674  "This will start the program:");
675 
676  QLabel *message = new QLabel(warningMessage, baseWidget);
677  contentLayout->addWidget(message);
678 
679  // We can use KStandardDirs::findExe to resolve relative pathnames
680  // but that gets rid of the command line arguments.
681  QString program = QFileInfo(service.exec()).canonicalFilePath();
682  if (program.isEmpty()) { // e.g. due to command line arguments
683  program = service.exec();
684  }
685 
686  QPlainTextEdit *textEdit = new QPlainTextEdit(baseWidget);
687  textEdit->setPlainText(program);
688  textEdit->setReadOnly(true);
689  contentLayout->addWidget(textEdit);
690 
691  QLabel *footerLabel = new QLabel(i18n("If you do not trust this program, click Cancel"));
692  contentLayout->addWidget(footerLabel);
693  contentLayout->addStretch(0); // Don't allow the text edit to expand
694 
695  mainLayout->addLayout(contentLayout);
696 
697  topLayout->addWidget(baseWidget);
698  baseDialog->setTextEdit(textEdit);
699 
700  QDialogButtonBox *buttonBox = new QDialogButtonBox(baseDialog);
701  buttonBox->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
702  KGuiItem::assign(buttonBox->button(QDialogButtonBox::Ok), KStandardGuiItem::cont());
703  buttonBox->button(QDialogButtonBox::Cancel)->setDefault(true);
704  buttonBox->button(QDialogButtonBox::Cancel)->setFocus();
705  QObject::connect(buttonBox, SIGNAL(accepted()), baseDialog, SLOT(accept()));
706  QObject::connect(buttonBox, SIGNAL(rejected()), baseDialog, SLOT(reject()));
707  topLayout->addWidget(buttonBox);
708 
709  // Constrain maximum size. Minimum size set in
710  // the dialog's show event.
711  QSize screenSize = QApplication::desktop()->screen()->size();
712  baseDialog->resize(screenSize.width() / 4, 50);
713  baseDialog->setMaximumHeight(screenSize.height() / 3);
714  baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
715 
716  int result = baseDialog->exec();
717  if (result != QDialog::Accepted) {
718  return false;
719  }
720 
721  // Assume that service is an absolute path since we're being called (relative paths
722  // would have been allowed unless Kiosk said no, therefore we already know where the
723  // .desktop file is. Now add a header to it if it doesn't already have one
724  // and add the +x bit.
725 
726  if (!::makeFileExecutable(service.entryPath())) {
727  QString serviceName = service.name();
728  if (serviceName.isEmpty()) {
729  serviceName = service.genericName();
730  }
731 
732  KMessageBox::sorry(
733  window,
734  i18n("Unable to make the service %1 executable, aborting execution", serviceName)
735  );
736 
737  return false;
738  }
739 
740  return true;
741 }
742 
743 bool KRun::run(const KService &_service, const QList<QUrl> &_urls, QWidget *window,
744  bool tempFiles, const QString &suggestedFileName, const QByteArray &asn)
745 {
746  return runService(_service, _urls, window, tempFiles, suggestedFileName, asn) != 0;
747 }
748 
749 qint64 KRun::runApplication(const KService &service, const QList<QUrl> &urls, QWidget *window,
750  RunFlags flags, const QString &suggestedFileName,
751  const QByteArray &asn)
752 {
753  if (!service.entryPath().isEmpty() &&
754  !KDesktopFile::isAuthorizedDesktopFile(service.entryPath()) &&
755  !::makeServiceExecutable(service, window)) {
756  return 0;
757  }
758 
759 
760  if ((flags & DeleteTemporaryFiles) == 0) {
761  // Remember we opened those urls, for the "recent documents" menu in kicker
762  for (const QUrl &url : urls) {
763  KRecentDocument::add(url, service.desktopEntryName());
764  }
765  }
766 
767  return runApplicationImpl(service, urls, window, flags, suggestedFileName, asn);
768 }
769 
770 qint64 KRun::runService(const KService &_service, const QList<QUrl> &_urls, QWidget *window,
771  bool tempFiles, const QString &suggestedFileName, const QByteArray &asn)
772 {
773  if (!_service.entryPath().isEmpty() &&
774  !KDesktopFile::isAuthorizedDesktopFile(_service.entryPath()) &&
775  !::makeServiceExecutable(_service, window)) {
776  return 0;
777  }
778 
779  if (!tempFiles) {
780  // Remember we opened those urls, for the "recent documents" menu in kicker
781  for (const QUrl &url : _urls) {
782  KRecentDocument::add(url, _service.desktopEntryName());
783  }
784  }
785 
786  bool useKToolInvocation = !(tempFiles || _service.entryPath().isEmpty() || !suggestedFileName.isEmpty());
787 
788  if (useKToolInvocation) {
789  // Is klauncher installed? Let's try to start it, if it fails, then we won't use it.
790  static int klauncherAvailable = -1;
791  if (klauncherAvailable == -1) {
792  KToolInvocation::ensureKdeinitRunning();
793  QDBusConnectionInterface *dbusDaemon = QDBusConnection::sessionBus().interface();
794  klauncherAvailable = dbusDaemon->isServiceRegistered(QStringLiteral("org.kde.klauncher5"));
795  }
796  if (klauncherAvailable == 0) {
797  useKToolInvocation = false;
798  }
799  }
800 
801  if (!useKToolInvocation) {
802  return runApplicationImpl(_service, _urls, window, tempFiles ? RunFlags(DeleteTemporaryFiles) : RunFlags(), suggestedFileName, asn);
803  }
804 
805  // Resolve urls if needed, depending on what the app supports
806  const QList<QUrl> urls = resolveURLs(_urls, _service);
807 
808  //qDebug() << "Running" << _service.entryPath() << _urls << "using klauncher";
809 
810  QString error;
811  int pid = 0; //TODO KF6: change KToolInvokation to take a qint64*
812 
813  QByteArray myasn = asn;
814  // startServiceByDesktopPath() doesn't take QWidget*, add it to the startup info now
815  if (window) {
816  if (myasn.isEmpty()) {
817  myasn = KStartupInfo::createNewStartupId();
818  }
819  if (myasn != "0") {
820  KStartupInfoId id;
821  id.initId(myasn);
822  KStartupInfoData data;
823  // QTBUG-59017 Calling winId() on an embedded widget will break interaction
824  // with it on high-dpi multi-screen setups (cf. also Bug 363548), hence using
825  // its parent window instead
826  if (window->window()) {
827  data.setLaunchedBy(window->window()->winId());
828  }
829  KStartupInfo::sendChange(id, data);
830  }
831  }
832 
833  int i = KToolInvocation::startServiceByDesktopPath(
834  _service.entryPath(), QUrl::toStringList(urls), &error, nullptr, &pid, myasn
835  );
836 
837  if (i != 0) {
838  //qDebug() << error;
839  KMessageBox::sorry(window, error);
840  return 0;
841  }
842 
843  //qDebug() << "startServiceByDesktopPath worked fine";
844  return pid;
845 }
846 
847 bool KRun::run(const QString &_exec, const QList<QUrl> &_urls, QWidget *window, const QString &_name,
848  const QString &_icon, const QByteArray &asn)
849 {
850  KService::Ptr service(new KService(_name, _exec, _icon));
851 
852  return runService(*service, _urls, window, false, QString(), asn);
853 }
854 
855 bool KRun::runCommand(const QString &cmd, QWidget *window, const QString &workingDirectory)
856 {
857  if (cmd.isEmpty()) {
858  qCWarning(KIO_WIDGETS) << "Command was empty, nothing to run";
859  return false;
860  }
861 
862  const QStringList args = KShell::splitArgs(cmd);
863  if (args.isEmpty()) {
864  qCWarning(KIO_WIDGETS) << "Command could not be parsed.";
865  return false;
866  }
867 
868  const QString bin = args.first();
869  return KRun::runCommand(cmd, bin, bin /*iconName*/, window, QByteArray(), workingDirectory);
870 }
871 
872 bool KRun::runCommand(const QString &cmd, const QString &execName, const QString &iconName, QWidget *window, const QByteArray &asn)
873 {
874  return runCommand(cmd, execName, iconName, window, asn, QString());
875 }
876 
877 bool KRun::runCommand(const QString &cmd, const QString &execName, const QString &iconName,
878  QWidget *window, const QByteArray &asn, const QString &workingDirectory)
879 {
880  //qDebug() << "runCommand " << cmd << "," << execName;
881  KProcess *proc = new KProcess;
882  proc->setShellCommand(cmd);
883  if (!workingDirectory.isEmpty()) {
884  proc->setWorkingDirectory(workingDirectory);
885  }
886  QString bin = KIO::DesktopExecParser::executableName(execName);
887  KService::Ptr service = KService::serviceByDesktopName(bin);
888  return runCommandInternal(proc, service.data(),
889  execName /*executable to check for in slotProcessExited*/,
890  execName /*user-visible name*/,
891  iconName, window, asn) != 0;
892 }
893 
894 KRun::KRun(const QUrl &url, QWidget *window,
895  bool showProgressInfo, const QByteArray &asn)
896  : d(new KRunPrivate(this))
897 {
898  d->m_timer = new QTimer(this);
899  d->m_timer->setObjectName(QStringLiteral("KRun::timer"));
900  d->m_timer->setSingleShot(true);
901  d->init(url, window, showProgressInfo, asn);
902 }
903 
904 void KRun::KRunPrivate::init(const QUrl &url, QWidget *window,
905  bool showProgressInfo, const QByteArray &asn)
906 {
907  m_bFault = false;
908  m_bAutoDelete = true;
909  m_bProgressInfo = showProgressInfo;
910  m_bFinished = false;
911  m_job = nullptr;
912  m_strURL = url;
913  m_bScanFile = false;
914  m_bIsDirectory = false;
915  m_runExecutables = true;
916  m_window = window;
917  m_asn = asn;
918  q->setEnableExternalBrowser(true);
919 
920  // Start the timer. This means we will return to the event
921  // loop and do initialization afterwards.
922  // Reason: We must complete the constructor before we do anything else.
923  m_bCheckPrompt = false;
924  m_bInit = true;
925  q->connect(m_timer, SIGNAL(timeout()), q, SLOT(slotTimeout()));
926  startTimer();
927  //qDebug() << "new KRun" << q << url << "timer=" << m_timer;
928 }
929 
930 void KRun::init()
931 {
932  //qDebug() << "INIT called";
933  if (!d->m_strURL.isValid() || d->m_strURL.scheme().isEmpty()) {
934  const QString error = !d->m_strURL.isValid() ? d->m_strURL.errorString() : d->m_strURL.toString();
935  handleInitError(KIO::ERR_MALFORMED_URL, i18n("Malformed URL\n%1", error));
936  qCWarning(KIO_WIDGETS) << "Malformed URL:" << error;
937  d->m_bFault = true;
938  d->m_bFinished = true;
939  d->startTimer();
940  return;
941  }
942  if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("open"), QUrl(), d->m_strURL)) {
943  QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->m_strURL.toDisplayString());
944  handleInitError(KIO::ERR_ACCESS_DENIED, msg);
945  d->m_bFault = true;
946  d->m_bFinished = true;
947  d->startTimer();
948  return;
949  }
950 
951  if (!d->m_externalBrowser.isEmpty() && d->m_strURL.scheme().startsWith(QLatin1String("http"))) {
952  if (d->runExecutable(d->m_externalBrowser)) {
953  return;
954  }
955  } else if (d->m_strURL.isLocalFile() &&
956  (d->m_strURL.host().isEmpty() ||
957  (d->m_strURL.host() == QLatin1String("localhost")) ||
958  (d->m_strURL.host().compare(QHostInfo::localHostName(), Qt::CaseInsensitive) == 0))) {
959  const QString localPath = d->m_strURL.toLocalFile();
960  if (!QFile::exists(localPath)) {
961  handleInitError(KIO::ERR_DOES_NOT_EXIST,
962  i18n("<qt>Unable to run the command specified. "
963  "The file or folder <b>%1</b> does not exist.</qt>",
964  localPath.toHtmlEscaped()));
965  d->m_bFault = true;
966  d->m_bFinished = true;
967  d->startTimer();
968  return;
969  }
970 
971  QMimeDatabase db;
972  QMimeType mime = db.mimeTypeForUrl(d->m_strURL);
973  //qDebug() << "MIME TYPE is " << mime.name();
974  if (!d->m_externalBrowser.isEmpty() && (
975  mime.inherits(QStringLiteral("text/html")) ||
976  mime.inherits(QStringLiteral("application/xhtml+xml")))) {
977  if (d->runExecutable(d->m_externalBrowser)) {
978  return;
979  }
980  } else if (mime.isDefault() && !QFileInfo(localPath).isReadable()) {
981  // Unknown mimetype because the file is unreadable, no point in showing an open-with dialog (#261002)
982  const QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, localPath);
983  handleInitError(KIO::ERR_ACCESS_DENIED, msg);
984  d->m_bFault = true;
985  d->m_bFinished = true;
986  d->startTimer();
987  return;
988  } else {
989  mimeTypeDetermined(mime.name());
990  return;
991  }
992  } else if (KIO::DesktopExecParser::hasSchemeHandler(d->m_strURL)) {
993  //qDebug() << "Using scheme handler";
994  const QString exec = schemeHandler(d->m_strURL.scheme());
995  if (exec.isEmpty()) {
996  mimeTypeDetermined(KProtocolManager::defaultMimetype(d->m_strURL));
997  return;
998  } else {
999  if (run(exec, QList<QUrl>() << d->m_strURL, d->m_window, QString(), QString(), d->m_asn)) {
1000  d->m_bFinished = true;
1001  d->startTimer();
1002  return;
1003  }
1004  }
1005  }
1006 
1007 #if 0 // removed for KF5 (for portability). Reintroduce a bool or flag if useful.
1008  // Did we already get the information that it is a directory ?
1009  if ((d->m_mode & QT_STAT_MASK) == QT_STAT_DIR) {
1010  mimeTypeDetermined("inode/directory");
1011  return;
1012  }
1013 #endif
1014 
1015  // Let's see whether it is a directory
1016 
1017  if (!KProtocolManager::supportsListing(d->m_strURL)) {
1018  // No support for listing => it can't be a directory (example: http)
1019 
1020  if (!KProtocolManager::supportsReading(d->m_strURL)) {
1021  // No support for reading files either => we can't do anything (example: mailto URL, with no associated app)
1022  handleInitError(KIO::ERR_UNSUPPORTED_ACTION, i18n("Could not find any application or handler for %1", d->m_strURL.toDisplayString()));
1023  d->m_bFault = true;
1024  d->m_bFinished = true;
1025  d->startTimer();
1026  return;
1027  }
1028  scanFile();
1029  return;
1030  }
1031 
1032  //qDebug() << "Testing directory (stating)";
1033 
1034  // It may be a directory or a file, let's stat
1035  KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
1036  KIO::StatJob *job = KIO::stat(d->m_strURL, KIO::StatJob::SourceSide, 0 /* no details */, flags);
1037  KJobWidgets::setWindow(job, d->m_window);
1038  connect(job, SIGNAL(result(KJob*)),
1039  this, SLOT(slotStatResult(KJob*)));
1040  d->m_job = job;
1041  //qDebug() << "Job" << job << "is about stating" << d->m_strURL;
1042 }
1043 
1044 KRun::~KRun()
1045 {
1046  //qDebug() << this;
1047  d->m_timer->stop();
1048  killJob();
1049  //qDebug() << this << "done";
1050  delete d;
1051 }
1052 
1053 bool KRun::KRunPrivate::runExecutable(const QString &_exec)
1054 {
1055  QList<QUrl> urls;
1056  urls.append(m_strURL);
1057  if (_exec.startsWith('!')) {
1058  QString exec = _exec.mid(1); // Literal command
1059  exec += QLatin1String(" %u");
1060  if (q->run(exec, urls, m_window, QString(), QString(), m_asn)) {
1061  m_bFinished = true;
1062  startTimer();
1063  return true;
1064  }
1065  } else {
1066  KService::Ptr service = KService::serviceByStorageId(_exec);
1067  if (service && q->runService(*service, urls, m_window, false, QString(), m_asn)) {
1068  m_bFinished = true;
1069  startTimer();
1070  return true;
1071  }
1072  }
1073  return false;
1074 }
1075 
1076 void KRun::KRunPrivate::showPrompt()
1077 {
1078  ExecutableFileOpenDialog *dialog = new ExecutableFileOpenDialog(q->window());
1079  dialog->setAttribute(Qt::WA_DeleteOnClose);
1080  connect(dialog, &ExecutableFileOpenDialog::finished, q, [this, dialog](int result){
1081  onDialogFinished(result, dialog->isDontAskAgainChecked());
1082  });
1083  dialog->show();
1084 }
1085 
1086 bool KRun::KRunPrivate::isPromptNeeded()
1087 {
1088  const QMimeDatabase db;
1089  const QMimeType mime = db.mimeTypeForUrl(m_strURL);
1090 
1091  const bool isFileExecutable = (isExecutableFile(m_strURL, mime.name()) ||
1092  mime.inherits(QStringLiteral("application/x-desktop")));
1093  const bool isTextFile = mime.inherits(QStringLiteral("text/plain"));
1094 
1095  if (isFileExecutable && isTextFile) {
1096  KConfigGroup cfgGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts");
1097  const QString value = cfgGroup.readEntry("behaviourOnLaunch", "alwaysAsk");
1098 
1099  if (value == QLatin1String("alwaysAsk")) {
1100  return true;
1101  } else {
1102  q->setRunExecutables(value == QLatin1String("execute"));
1103  }
1104  }
1105 
1106  return false;
1107 }
1108 
1109 void KRun::KRunPrivate::onDialogFinished(int result, bool isDontAskAgainSet)
1110 {
1111  if (result == ExecutableFileOpenDialog::Rejected) {
1112  m_bFinished = true;
1113  m_bInit = false;
1114  startTimer();
1115  return;
1116  }
1117  q->setRunExecutables(result == ExecutableFileOpenDialog::ExecuteFile);
1118 
1119  if (isDontAskAgainSet) {
1120  QString output = result == ExecutableFileOpenDialog::OpenFile ? QStringLiteral("open") : QStringLiteral("execute");
1121  KConfigGroup cfgGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts");
1122  cfgGroup.writeEntry("behaviourOnLaunch", output);
1123  }
1124  startTimer();
1125 }
1126 
1127 void KRun::scanFile()
1128 {
1129  //qDebug() << d->m_strURL;
1130  // First, let's check for well-known extensions
1131  // Not when there is a query in the URL, in any case.
1132  if (!d->m_strURL.hasQuery()) {
1133  QMimeDatabase db;
1134  QMimeType mime = db.mimeTypeForUrl(d->m_strURL);
1135  if (!mime.isDefault() || d->m_strURL.isLocalFile()) {
1136  //qDebug() << "Scanfile: MIME TYPE is " << mime.name();
1137  mimeTypeDetermined(mime.name());
1138  return;
1139  }
1140  }
1141 
1142  // No mimetype found, and the URL is not local (or fast mode not allowed).
1143  // We need to apply the 'KIO' method, i.e. either asking the server or
1144  // getting some data out of the file, to know what mimetype it is.
1145 
1146  if (!KProtocolManager::supportsReading(d->m_strURL)) {
1147  qCWarning(KIO_WIDGETS) << "#### NO SUPPORT FOR READING!";
1148  d->m_bFault = true;
1149  d->m_bFinished = true;
1150  d->startTimer();
1151  return;
1152  }
1153  //qDebug() << this << "Scanning file" << d->m_strURL;
1154 
1155  KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
1156  KIO::TransferJob *job = KIO::get(d->m_strURL, KIO::NoReload /*reload*/, flags);
1157  KJobWidgets::setWindow(job, d->m_window);
1158  connect(job, SIGNAL(result(KJob*)),
1159  this, SLOT(slotScanFinished(KJob*)));
1160  connect(job, SIGNAL(mimetype(KIO::Job*,QString)),
1161  this, SLOT(slotScanMimeType(KIO::Job*,QString)));
1162  d->m_job = job;
1163  //qDebug() << "Job" << job << "is about getting from" << d->m_strURL;
1164 }
1165 
1166 // When arriving in that method there are 6 possible states:
1167 // must_show_prompt, must_init, must_scan_file, found_dir, done+error or done+success.
1168 void KRun::slotTimeout()
1169 {
1170  if (d->m_bCheckPrompt) {
1171  d->m_bCheckPrompt = false;
1172  if (d->isPromptNeeded()) {
1173  d->showPrompt();
1174  return;
1175  }
1176  }
1177  if (d->m_bInit) {
1178  d->m_bInit = false;
1179  init();
1180  return;
1181  }
1182 
1183  if (d->m_bFault) {
1184  emit error();
1185  }
1186  if (d->m_bFinished) {
1187  emit finished();
1188  } else {
1189  if (d->m_bScanFile) {
1190  d->m_bScanFile = false;
1191  scanFile();
1192  return;
1193  } else if (d->m_bIsDirectory) {
1194  d->m_bIsDirectory = false;
1195  mimeTypeDetermined(QStringLiteral("inode/directory"));
1196  return;
1197  }
1198  }
1199 
1200  if (d->m_bAutoDelete) {
1201  deleteLater();
1202  return;
1203  }
1204 }
1205 
1206 void KRun::slotStatResult(KJob *job)
1207 {
1208  d->m_job = nullptr;
1209  const int errCode = job->error();
1210  if (errCode) {
1211  // ERR_NO_CONTENT is not an error, but an indication no further
1212  // actions needs to be taken.
1213  if (errCode != KIO::ERR_NO_CONTENT) {
1214  qCWarning(KIO_WIDGETS) << this << "ERROR" << job->error() << job->errorString();
1215  handleError(job);
1216  //qDebug() << this << " KRun returning from showErrorDialog, starting timer to delete us";
1217  d->m_bFault = true;
1218  }
1219 
1220  d->m_bFinished = true;
1221 
1222  // will emit the error and autodelete this
1223  d->startTimer();
1224  } else {
1225  //qDebug() << "Finished";
1226 
1227  KIO::StatJob *statJob = qobject_cast<KIO::StatJob *>(job);
1228  if (!statJob) {
1229  qFatal("Fatal Error: job is a %s, should be a StatJob", typeid(*job).name());
1230  }
1231 
1232  // Update our URL in case of a redirection
1233  setUrl(statJob->url());
1234 
1235  const KIO::UDSEntry entry = statJob->statResult();
1236  const mode_t mode = entry.numberValue(KIO::UDSEntry::UDS_FILE_TYPE);
1237  if ((mode & QT_STAT_MASK) == QT_STAT_DIR) {
1238  d->m_bIsDirectory = true; // it's a dir
1239  } else {
1240  d->m_bScanFile = true; // it's a file
1241  }
1242 
1243  d->m_localPath = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
1244 
1245  // mimetype already known? (e.g. print:/manager)
1246  const QString knownMimeType = entry.stringValue(KIO::UDSEntry::UDS_MIME_TYPE);
1247 
1248  if (!knownMimeType.isEmpty()) {
1249  mimeTypeDetermined(knownMimeType);
1250  d->m_bFinished = true;
1251  }
1252 
1253  // We should have found something
1254  assert(d->m_bScanFile || d->m_bIsDirectory);
1255 
1256  // Start the timer. Once we get the timer event this
1257  // protocol server is back in the pool and we can reuse it.
1258  // This gives better performance than starting a new slave
1259  d->startTimer();
1260  }
1261 }
1262 
1263 void KRun::slotScanMimeType(KIO::Job *, const QString &mimetype)
1264 {
1265  if (mimetype.isEmpty()) {
1266  qCWarning(KIO_WIDGETS) << "get() didn't emit a mimetype! Probably a kioslave bug, please check the implementation of" << url().scheme();
1267  }
1268  mimeTypeDetermined(mimetype);
1269  d->m_job = nullptr;
1270 }
1271 
1272 void KRun::slotScanFinished(KJob *job)
1273 {
1274  d->m_job = nullptr;
1275  const int errCode = job->error();
1276  if (errCode) {
1277  // ERR_NO_CONTENT is not an error, but an indication no further
1278  // actions needs to be taken.
1279  if (errCode != KIO::ERR_NO_CONTENT) {
1280  qCWarning(KIO_WIDGETS) << this << "ERROR (stat):" << job->error() << ' ' << job->errorString();
1281  handleError(job);
1282 
1283  d->m_bFault = true;
1284  }
1285 
1286  d->m_bFinished = true;
1287  // will emit the error and autodelete this
1288  d->startTimer();
1289  }
1290 }
1291 
1292 void KRun::mimeTypeDetermined(const QString &mimeType)
1293 {
1294  // foundMimeType reimplementations might show a dialog box;
1295  // make sure some timer doesn't kill us meanwhile (#137678, #156447)
1296  Q_ASSERT(!d->m_showingDialog);
1297  d->m_showingDialog = true;
1298 
1299  foundMimeType(mimeType);
1300 
1301  d->m_showingDialog = false;
1302 
1303  // We cannot assume that we're finished here. Some reimplementations
1304  // start a KIO job and call setFinished only later.
1305 }
1306 
1307 void KRun::foundMimeType(const QString &type)
1308 {
1309  //qDebug() << "Resulting mime type is " << type;
1310 
1311  QMimeDatabase db;
1312 
1313  KIO::TransferJob *job = qobject_cast<KIO::TransferJob *>(d->m_job);
1314  if (job) {
1315  // Update our URL in case of a redirection
1316  setUrl(job->url());
1317 
1318  job->putOnHold();
1319  KIO::Scheduler::publishSlaveOnHold();
1320  d->m_job = nullptr;
1321  }
1322 
1323  Q_ASSERT(!d->m_bFinished);
1324 
1325  // Support for preferred service setting, see setPreferredService
1326  if (!d->m_preferredService.isEmpty()) {
1327  //qDebug() << "Attempting to open with preferred service: " << d->m_preferredService;
1328  KService::Ptr serv = KService::serviceByDesktopName(d->m_preferredService);
1329  if (serv && serv->hasMimeType(type)) {
1330  QList<QUrl> lst;
1331  lst.append(d->m_strURL);
1332  if (KRun::runService(*serv, lst, d->m_window, false, QString(), d->m_asn)) {
1333  setFinished(true);
1334  return;
1335  }
1340  }
1341  }
1342 
1343  // Resolve .desktop files from media:/, remote:/, applications:/ etc.
1344  QMimeType mime = db.mimeTypeForName(type);
1345  if (!mime.isValid()) {
1346  qCWarning(KIO_WIDGETS) << "Unknown mimetype " << type;
1347  } else if (mime.inherits(QStringLiteral("application/x-desktop")) && !d->m_localPath.isEmpty()) {
1348  d->m_strURL = QUrl::fromLocalFile(d->m_localPath);
1349  }
1350 
1351  if (!KRun::runUrl(d->m_strURL, type, d->m_window, false /*tempfile*/, d->m_runExecutables, d->m_suggestedFileName, d->m_asn)) {
1352  d->m_bFault = true;
1353  }
1354  setFinished(true);
1355 }
1356 
1357 void KRun::killJob()
1358 {
1359  if (d->m_job) {
1360  //qDebug() << this << "m_job=" << d->m_job;
1361  d->m_job->kill();
1362  d->m_job = nullptr;
1363  }
1364 }
1365 
1366 void KRun::abort()
1367 {
1368  if (d->m_bFinished) {
1369  return;
1370  }
1371  //qDebug() << this << "m_showingDialog=" << d->m_showingDialog;
1372  killJob();
1373  // If we're showing an error message box, the rest will be done
1374  // after closing the msgbox -> don't autodelete nor emit signals now.
1375  if (d->m_showingDialog) {
1376  return;
1377  }
1378  d->m_bFault = true;
1379  d->m_bFinished = true;
1380  d->m_bInit = false;
1381  d->m_bScanFile = false;
1382 
1383  // will emit the error and autodelete this
1384  d->startTimer();
1385 }
1386 
1387 QWidget *KRun::window() const
1388 {
1389  return d->m_window;
1390 }
1391 
1392 bool KRun::hasError() const
1393 {
1394  return d->m_bFault;
1395 }
1396 
1397 bool KRun::hasFinished() const
1398 {
1399  return d->m_bFinished;
1400 }
1401 
1402 bool KRun::autoDelete() const
1403 {
1404  return d->m_bAutoDelete;
1405 }
1406 
1407 void KRun::setAutoDelete(bool b)
1408 {
1409  d->m_bAutoDelete = b;
1410 }
1411 
1412 void KRun::setEnableExternalBrowser(bool b)
1413 {
1414  if (b) {
1415  d->m_externalBrowser = KConfigGroup(KSharedConfig::openConfig(), "General").readEntry("BrowserApplication");
1416  } else {
1417  d->m_externalBrowser.clear();
1418  }
1419 }
1420 
1421 void KRun::setPreferredService(const QString &desktopEntryName)
1422 {
1423  d->m_preferredService = desktopEntryName;
1424 }
1425 
1426 void KRun::setRunExecutables(bool b)
1427 {
1428  d->m_runExecutables = b;
1429 }
1430 
1431 void KRun::setSuggestedFileName(const QString &fileName)
1432 {
1433  d->m_suggestedFileName = fileName;
1434 }
1435 
1436 void KRun::setShowScriptExecutionPrompt(bool showPrompt)
1437 {
1438  d->m_bCheckPrompt = showPrompt;
1439 }
1440 
1441 QString KRun::suggestedFileName() const
1442 {
1443  return d->m_suggestedFileName;
1444 }
1445 
1446 bool KRun::isExecutable(const QString &serviceType)
1447 {
1448  return (serviceType == QLatin1String("application/x-desktop") ||
1449  serviceType == QLatin1String("application/x-executable") ||
1450  /* See https://bugs.freedesktop.org/show_bug.cgi?id=97226 */
1451  serviceType == QLatin1String("application/x-sharedlib") ||
1452  serviceType == QLatin1String("application/x-ms-dos-executable") ||
1453  serviceType == QLatin1String("application/x-shellscript"));
1454 }
1455 
1456 void KRun::setUrl(const QUrl &url)
1457 {
1458  d->m_strURL = url;
1459 }
1460 
1461 QUrl KRun::url() const
1462 {
1463  return d->m_strURL;
1464 }
1465 
1466 void KRun::setError(bool error)
1467 {
1468  d->m_bFault = error;
1469 }
1470 
1471 void KRun::setProgressInfo(bool progressInfo)
1472 {
1473  d->m_bProgressInfo = progressInfo;
1474 }
1475 
1476 bool KRun::progressInfo() const
1477 {
1478  return d->m_bProgressInfo;
1479 }
1480 
1481 void KRun::setFinished(bool finished)
1482 {
1483  d->m_bFinished = finished;
1484  if (finished) {
1485  d->startTimer();
1486  }
1487 }
1488 
1489 void KRun::setJob(KIO::Job *job)
1490 {
1491  d->m_job = job;
1492 }
1493 
1494 KIO::Job *KRun::job()
1495 {
1496  return d->m_job;
1497 }
1498 
1499 #ifndef KIOWIDGETS_NO_DEPRECATED
1500 QTimer &KRun::timer()
1501 {
1502  return *d->m_timer;
1503 }
1504 #endif
1505 
1506 #ifndef KIOWIDGETS_NO_DEPRECATED
1507 void KRun::setDoScanFile(bool scanFile)
1508 {
1509  d->m_bScanFile = scanFile;
1510 }
1511 #endif
1512 
1513 #ifndef KIOWIDGETS_NO_DEPRECATED
1514 bool KRun::doScanFile() const
1515 {
1516  return d->m_bScanFile;
1517 }
1518 #endif
1519 
1520 #ifndef KIOWIDGETS_NO_DEPRECATED
1521 void KRun::setIsDirecory(bool isDirectory)
1522 {
1523  d->m_bIsDirectory = isDirectory;
1524 }
1525 #endif
1526 
1527 bool KRun::isDirectory() const
1528 {
1529  return d->m_bIsDirectory;
1530 }
1531 
1532 #ifndef KIOWIDGETS_NO_DEPRECATED
1533 void KRun::setInitializeNextAction(bool initialize)
1534 {
1535  d->m_bInit = initialize;
1536 }
1537 #endif
1538 
1539 #ifndef KIOWIDGETS_NO_DEPRECATED
1540 bool KRun::initializeNextAction() const
1541 {
1542  return d->m_bInit;
1543 }
1544 #endif
1545 
1546 bool KRun::isLocalFile() const
1547 {
1548  return d->m_strURL.isLocalFile();
1549 }
1550 
1551 /****************/
1552 
1553 qint64 KProcessRunner::run(KProcess *p, const QString &executable, const KStartupInfoId &id)
1554 {
1555  return (new KProcessRunner(p, executable, id))->pid();
1556 }
1557 
1558 KProcessRunner::KProcessRunner(KProcess *p, const QString &executable, const KStartupInfoId &id) :
1559  id(id)
1560 {
1561  m_pid = 0;
1562  process = p;
1563  m_executable = executable;
1564  connect(process, SIGNAL(finished(int,QProcess::ExitStatus)),
1565  this, SLOT(slotProcessExited(int,QProcess::ExitStatus)));
1566 
1567  process->start();
1568  if (!process->waitForStarted()) {
1569  //qDebug() << "wait for started failed, exitCode=" << process->exitCode()
1570  // << "exitStatus=" << process->exitStatus();
1571  // Note that exitCode is 255 here (the first time), and 0 later on (bug?).
1572  slotProcessExited(255, process->exitStatus());
1573  } else {
1574  m_pid = process->processId();
1575  }
1576 }
1577 
1578 KProcessRunner::~KProcessRunner()
1579 {
1580  delete process;
1581 }
1582 
1583 qint64 KProcessRunner::pid() const
1584 {
1585  return m_pid;
1586 }
1587 
1588 void KProcessRunner::terminateStartupNotification()
1589 {
1590 #if HAVE_X11
1591  if (!id.isNull()) {
1592  KStartupInfoData data;
1593  data.addPid(m_pid); // announce this pid for the startup notification has finished
1594  data.setHostname();
1595  KStartupInfo::sendFinish(id, data);
1596  }
1597 #endif
1598 
1599 }
1600 
1601 void
1602 KProcessRunner::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
1603 {
1604  //qDebug() << m_executable << "exitCode=" << exitCode << "exitStatus=" << exitStatus;
1605  Q_UNUSED(exitStatus);
1606 
1607  terminateStartupNotification(); // do this before the messagebox
1608  if (exitCode != 0 && !m_executable.isEmpty()) {
1609  // Let's see if the error is because the exe doesn't exist.
1610  // When this happens, waitForStarted returns false, but not if kioexec
1611  // was involved, then we come here, that's why the code is here.
1612  //
1613  // We'll try to find the executable relatively to current directory,
1614  // (or with a full path, if m_executable is absolute), and then in the PATH.
1615  if (!QFile(m_executable).exists() && QStandardPaths::findExecutable(m_executable).isEmpty()) {
1616  QEventLoopLocker locker;
1617  KMessageBox::sorry(nullptr, i18n("Could not find the program '%1'", m_executable));
1618  } else {
1619  //qDebug() << process->readAllStandardError();
1620  }
1621  }
1622  deleteLater();
1623 }
1624 
1625 #include "moc_krun.cpp"
1626 #include "moc_krun_p.cpp"
1627 #include "krun.moc"
KStartupInfo::resetStartupEnv
static void resetStartupEnv()
KJobWidgets::setWindow
KJOBWIDGETS_EXPORT void setWindow(KJob *job, QWidget *widget)
KProcess::setShellCommand
void setShellCommand(const QString &cmd)
QList::clear
void clear()
QFileInfo::isReadable
bool isReadable() const
KRemoteEncoding::fileName
QByteArray fileName(const QUrl &url) const
Converts the given URL into 8-bit form and retrieve the filename.
Definition: kremoteencoding.cpp:90
QSaveFile
KRun::run
static KIOWIDGETS_DEPRECATED bool run(const KService &service, const QList< QUrl > &urls, QWidget *window, bool tempFiles=false, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Open a list of URLs with a certain service (application).
Definition: krun.cpp:743
KRun::setEnableExternalBrowser
void setEnableExternalBrowser(bool b)
Sets whether the external webbrowser setting should be honoured.
Definition: krun.cpp:1412
QWidget
KRun::displayOpenWithDialog
static bool displayOpenWithDialog(const QList< QUrl > &lst, QWidget *window, bool tempFiles=false, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Display the Open-With dialog for those URLs, and run the chosen application.
Definition: krun.cpp:251
QString::append
QString & append(QChar ch)
KProcess
QUrl::toDisplayString
QString toDisplayString(QFlags< QUrl::UrlFormattingOption > options) const
QSize::width
int width() const
KProtocolManager::supportsReading
static bool supportsReading(const QUrl &url)
Returns whether the protocol can retrieve data from URLs.
Definition: kprotocolmanager.cpp:1166
KRun::slotTimeout
void slotTimeout()
All following protected slots are used by subclasses of KRun!
Definition: krun.cpp:1168
KRun::foundMimeType
virtual void foundMimeType(const QString &type)
Called if the mimetype has been detected.
Definition: krun.cpp:1307
KRun::abort
void abort()
Abort this KRun.
Definition: krun.cpp:1366
KRun::setDoScanFile
KIOWIDGETS_DEPRECATED void setDoScanFile(bool scanFile)
Indicate that the next action is to scan the file.
Definition: krun.cpp:1507
KRun::progressInfo
bool progressInfo() const
Returns whether progress information are shown.
Definition: krun.cpp:1476
KService::runOnDiscreteGpu
bool runOnDiscreteGpu() const
KRun::setIsDirecory
KIOWIDGETS_DEPRECATED void setIsDirecory(bool isDirectory)
Sets whether it is a directory.
Definition: krun.cpp:1521
QWidget::window
QWidget * window() const
QByteArray
KIO::SimpleJob::url
const QUrl & url() const
Returns the SimpleJob&#39;s URL.
Definition: simplejob.cpp:82
KIO::UDSEntry
Universal Directory Service.
Definition: udsentry.h:69
KDesktopFileActions::runWithStartup
KIOWIDGETS_EXPORT bool runWithStartup(const QUrl &_url, bool _is_local, const QByteArray &asn)
Invokes the default action for the desktop entry.
Definition: kdesktopfileactions.cpp:65
KService::serviceByDesktopName
static Ptr serviceByDesktopName(const QString &_name)
QWidget::setWindowModality
void setWindowModality(Qt::WindowModality windowModality)
QIODevice::errorString
QString errorString() const
QEventLoopLocker
QChar
QString::prepend
QString & prepend(QChar ch)
KJob::errorString
virtual QString errorString() const
KRun::setRunExecutables
void setRunExecutables(bool b)
Sets whether executables, .desktop files or shell scripts should be run by KRun.
Definition: krun.cpp:1426
KService
KIO::HideProgressInfo
Hide progress information dialog, i.e.
Definition: job_base.h:288
QMimeType::isValid
bool isValid() const
QUrl::toStringList
QStringList toStringList(const QList< QUrl > &urls, QFlags< QUrl::UrlFormattingOption > options)
QLabel::setPixmap
void setPixmap(const QPixmap &)
KRun::isExecutableFile
static bool isExecutableFile(const QUrl &url, const QString &mimetype)
Returns whether the url of mimetype is executable.
Definition: krun.cpp:129
QMimeDatabase
KService::property
QVariant property(const QString &_name, QVariant::Type t) const
KRun::setUrl
void setUrl(const QUrl &url)
Sets the url.
Definition: krun.cpp:1456
KJob::exec
bool exec()
KIO::UDSEntry::UDS_FILE_TYPE
File type, part of the mode returned by stat (for a link, this returns the file type of the pointed i...
Definition: udsentry.h:211
KIO::DesktopExecParser::isProtocolInSupportedList
static bool isProtocolInSupportedList(const QUrl &url, const QStringList &supportedProtocols)
Returns true if protocol is in the list of protocols returned by supportedProtocols().
Definition: desktopexecparser.cpp:203
QStringList::contains
bool contains(const QString &str, Qt::CaseSensitivity cs) const
QByteArray::isEmpty
bool isEmpty() const
KRun::url
QUrl url() const
Returns the url.
Definition: krun.cpp:1461
KRun::isDirectory
bool isDirectory() const
Returns whether it is a directory.
Definition: krun.cpp:1527
QMimeType::isDefault
bool isDefault() const
QStandardPaths::findExecutable
QString findExecutable(const QString &executableName, const QStringList &paths)
QHBoxLayout
QMimeType::inherits
bool inherits(const QString &mimeTypeName) const
QDialog::exec
virtual int exec()
QPlainTextEdit
KConfigGroup::writeEntry
void writeEntry(const QString &key, const QVariant &value, WriteConfigFlags pFlags=Normal)
KStartupInfoId
KService::genericName
QString genericName() const
KIO::StatJob
A KIO job that retrieves information about a file or directory.
Definition: statjob.h:37
KRun::runService
static qint64 runService(const KService &service, const QList< QUrl > &urls, QWidget *window, bool tempFiles=false, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Open a list of URLs with a certain service (application).
Definition: krun.cpp:770
KIO::UDSEntry::UDS_LOCAL_PATH
A local file path if the ioslave display files sitting on the local filesystem (but in another hierar...
Definition: udsentry.h:196
QSaveFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
KRun::runUrl
static bool KIOWIDGETS_DEPRECATED runUrl(const QUrl &url, const QString &mimetype, QWidget *window, bool tempFile=false, bool runExecutables=true, const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Open the given URL.
Definition: krun.cpp:170
QFile::setPermissions
virtual bool setPermissions(QFlags< QFileDevice::Permission > permissions)
KRun::hasError
bool hasError() const
Returns true if the KRun instance has an error.
Definition: krun.cpp:1392
QFontMetrics
QFile::exists
bool exists() const
KStandardGuiItem::cont
KGuiItem cont()
KIconLoader::NoGroup
NoGroup
KRun::initializeNextAction
KIOWIDGETS_DEPRECATED bool initializeNextAction() const
Definition: krun.cpp:1540
KStartupInfoData::setBin
void setBin(const QString &bin)
KRun::scanFile
virtual void scanFile()
Start scanning a file.
Definition: krun.cpp:1127
KRun::checkStartupNotify
static bool checkStartupNotify(const QString &binName, const KService *service, bool *silent_arg, QByteArray *wmclass_arg)
Definition: krun.cpp:382
KStartupInfoData::setName
void setName(const QString &name)
QFile
KService::isApplication
bool isApplication() const
KIO::DesktopExecParser::setSuggestedFileName
void setSuggestedFileName(const QString &suggestedFileName)
Sets the file name to use in the case of downloading the file to a tempfile in order to give to a non...
Definition: desktopexecparser.cpp:252
KRun
To open files with their associated applications in KDE, use KRun.
Definition: krun.h:62
KService::exec
QString exec() const
KRun::slotScanMimeType
void slotScanMimeType(KIO::Job *, const QString &type)
This slot is called when the scan job has found out the mime type.
Definition: krun.cpp:1263
KRecentDocument::add
static void add(const QUrl &url)
Add a new item to the Recent Document menu.
Definition: krecentdocument.cpp:87
KRun::processDesktopExec
static KIOWIDGETS_DEPRECATED QStringList processDesktopExec(const KService &_service, const QList< QUrl > &_urls, bool tempFiles=false, const QString &suggestedFileName=QString())
Processes a Exec= line as found in .desktop files.
Definition: krun.cpp:292
KDesktopFile::isAuthorizedDesktopFile
static bool isAuthorizedDesktopFile(const QString &path)
KService::path
QString path() const
QIODevice::peek
qint64 peek(char *data, qint64 maxSize)
KIO::DefaultFlags
Show the progress info GUI, no Resume and no Overwrite.
Definition: job_base.h:283
QWidget::size
size
KStartupInfo::sendChange
static bool sendChange(const KStartupInfoId &id, const KStartupInfoData &data)
QRect
KRun::setError
void setError(bool error)
Sets whether an error has occurred.
Definition: krun.cpp:1466
KIO::DesktopExecParser::resultingArguments
QStringList resultingArguments() const
Definition: desktopexecparser.cpp:266
KWindowSystem::currentDesktop
static int currentDesktop()
QBoxLayout::addWidget
void addWidget(QWidget *widget, int stretch, Qt::Alignment alignment)
QList::count
int count(const T &value) const
QList::append
void append(const T &value)
KRun::DeleteTemporaryFiles
the URLs passed to the service will be deleted when it exits (if the URLs are local files) ...
Definition: krun.h:236
KStartupInfoData::setDescription
void setDescription(const QString &descr)
KStartupInfo::sendStartup
static bool sendStartup(const KStartupInfoId &id, const KStartupInfoData &data)
KRun::finished
void finished()
Emitted when the operation finished.
KSycocaEntry::entryPath
QString entryPath() const
KRun::isExecutable
static bool isExecutable(const QString &serviceType)
Returns whether serviceType refers to an executable program instead of a data file.
Definition: krun.cpp:1446
QWidget::topLevelWidget
QWidget * topLevelWidget() const
QSaveFile::commit
bool commit()
QTimer
KStartupInfoData
KIO::UDSEntry::numberValue
long long numberValue(uint field, long long defaultValue=0) const
Definition: udsentry.cpp:119
QMimeDatabase::mimeTypeForUrl
QMimeType mimeTypeForUrl(const QUrl &url) const
KStartupInfoData::setIcon
void setIcon(const QString &icon)
i18nc
QString i18nc(const char *context, const char *text, const TYPE &arg...)
QShowEvent
KProcess::setEnv
void setEnv(const QString &name, const QString &value, bool overwrite=true)
QWidget::setFocus
void setFocus()
KProtocolManager::defaultMimetype
static QString defaultMimetype(const QUrl &url)
Returns default mimetype for this URL based on the protocol.
Definition: kprotocolmanager.cpp:1296
KRun::window
QWidget * window() const
Associated window, as passed to the constructor.
Definition: krun.cpp:1387
QMimeType
QList::isEmpty
bool isEmpty() const
KRun::killJob
virtual void killJob()
Kills the file scanning job.
Definition: krun.cpp:1357
KProtocolManager::supportsListing
static bool supportsListing(const QUrl &url)
Returns whether the protocol can list files/objects.
Definition: kprotocolmanager.cpp:1146
KStartupInfoData::name
const QString & name() const
QString::isEmpty
bool isEmpty() const
KStartupInfoData::setSilent
void setSilent(TriState state)
KMimeTypeTrader::preferredService
KService::Ptr preferredService(const QString &mimeType, const QString &genericServiceType=QStringLiteral("Application"))
KRun::slotStatResult
virtual void slotStatResult(KJob *)
This slot is called when the &#39;stat&#39; job has finished.
Definition: krun.cpp:1206
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
KIO::buildErrorString
KIOCORE_EXPORT QString buildErrorString(int errorCode, const QString &errorText)
Returns a translated error message for errorCode using the additional error information provided by e...
Definition: job_error.cpp:33
QIODevice::readAll
QByteArray readAll()
KMessageBox::error
void error(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
KRun::autoDelete
bool autoDelete() const
Checks whether auto delete is activated.
Definition: krun.cpp:1402
KIO::StatJob::mostLocalUrl
QUrl mostLocalUrl() const
most local URL Call this in the slot connected to result, and only after making sure no error happene...
Definition: statjob.cpp:98
KRun::job
KIO::Job * job()
Returns the job.
Definition: krun.cpp:1494
KRun::handleInitError
virtual void handleInitError(int kioErrorCode, const QString &errorMsg)
Called when KRun detects an error during the init phase.
Definition: krun.cpp:151
KOpenWithDialog
"Open With" dialog box.
Definition: kopenwithdialog.h:45
KMimeTypeTrader::self
static KMimeTypeTrader * self()
QVBoxLayout
KRun::doScanFile
KIOWIDGETS_DEPRECATED bool doScanFile() const
Returns whether the file shall be scanned.
Definition: krun.cpp:1514
KIO::DesktopExecParser::supportedProtocols
static QStringList supportedProtocols(const KService &service)
Returns the list of protocols which the application supports.
Definition: desktopexecparser.cpp:174
KRun::setSuggestedFileName
void setSuggestedFileName(const QString &fileName)
Sets the file name to use in the case of downloading the file to a tempfile in order to give to a non...
Definition: krun.cpp:1431
QWidget::winId
WId winId() const
QObject::deleteLater
void deleteLater()
KStartupInfoData::setHostname
void setHostname(const QByteArray &hostname=QByteArray())
QList::first
T & first()
KRun::slotScanFinished
void slotScanFinished(KJob *)
This slot is called when the scan job is finished.
Definition: krun.cpp:1272
QString
QList< QUrl >
KProtocolInfo::protocolClass
static QString protocolClass(const QString &protocol)
Returns the protocol class for the specified protocol.
Definition: kprotocolinfo.cpp:329
KIO::DesktopExecParser::setUrlsAreTempFiles
void setUrlsAreTempFiles(bool tempFiles)
If tempFiles is set to true and the urls given to the constructor are local files, they will be deleted when the application exits.
Definition: desktopexecparser.cpp:247
KToolInvocation::startServiceByDesktopPath
static int startServiceByDesktopPath(const QString &_name, const QString &URL, QString *error=nullptr, QString *serviceName=nullptr, int *pid=nullptr, const QByteArray &startup_id=QByteArray(), bool noWait=false)
KShell::splitArgs
KCOREADDONS_EXPORT QStringList splitArgs(const QString &cmd, Options flags=NoOptions, Errors *err=nullptr)
KJob::uiDelegate
KJobUiDelegate * uiDelegate() const
QFile::open
virtual bool open(QFlags< QIODevice::OpenModeFlag > mode)
QUrl::scheme
QString scheme() const
KIconLoader::global
static KIconLoader * global()
QMimeDatabase::mimeTypeForName
QMimeType mimeTypeForName(const QString &nameOrAlias) const
QStringList
KStartupInfoData::setApplicationId
void setApplicationId(const QString &desktop)
KService::allowMultipleFiles
bool allowMultipleFiles() const
QPixmap
KToolInvocation::ensureKdeinitRunning
static void ensureKdeinitRunning()
QUrl::toLocalFile
QString toLocalFile() const
KIO::get
KIOCORE_EXPORT TransferJob * get(const QUrl &url, LoadType reload=NoReload, JobFlags flags=DefaultFlags)
Get (means: read).
Definition: transferjob.cpp:485
QFileInfo
QList::end
iterator end()
KRun::mimeTypeDetermined
void mimeTypeDetermined(const QString &mimeType)
Call this from subclasses when you have determined the mimetype.
Definition: krun.cpp:1292
QDesktopWidget::screen
QWidget * screen(int screen)
KShell::quoteArg
KCOREADDONS_EXPORT QString quoteArg(const QString &arg)
KService::icon
QString icon() const
QString::toHtmlEscaped
QString toHtmlEscaped() const
QSize
QUrl
QProcess::setWorkingDirectory
void setWorkingDirectory(const QString &dir)
KStartupInfo::sendFinish
static bool sendFinish(const KStartupInfoId &id)
KProtocolInfo::exec
static QString exec(const QString &protocol)
Returns the library / executable to open for the protocol protocol Example : "kio_ftp", meaning either the executable "kio_ftp" or the library "kio_ftp.la" (recommended), whichever is available.
Definition: kprotocolinfo.cpp:300
KSharedConfig::openConfig
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
KIconLoader::SizeHuge
SizeHuge
KOpenWithDialog::text
QString text() const
Definition: kopenwithdialog.cpp:1007
i18n
QString i18n(const char *text, const TYPE &arg...)
KConfigGroup
QString::replace
QString & replace(int position, int n, QChar after)
KRun::RunExecutables
Whether to run URLs that are executable scripts or binaries.
Definition: krun.h:237
KRun::handleError
virtual void handleError(KJob *job)
Called when a KIO job started by KRun gives an error.
Definition: krun.cpp:159
QObject::startTimer
int startTimer(int interval, Qt::TimerType timerType)
QPlainTextEdit::setReadOnly
void setReadOnly(bool ro)
QSaveFile::cancelWriting
void cancelWriting()
KRun::setInitializeNextAction
KIOWIDGETS_DEPRECATED void setInitializeNextAction(bool initialize)
Definition: krun.cpp:1533
KRun::setPreferredService
void setPreferredService(const QString &desktopEntryName)
Set the preferred service for opening this URL, after its mimetype will have been found by KRun...
Definition: krun.cpp:1421
KStartupInfoData::setWMClass
void setWMClass(const QByteArray &wmclass)
QString::toLatin1
QByteArray toLatin1() const
QString::mid
QString mid(int position, int n) const
KRun::isLocalFile
bool isLocalFile() const
Returns whether it is a local file.
Definition: krun.cpp:1546
KRun::suggestedFileName
QString suggestedFileName() const
Suggested file name given by the server (e.g.
Definition: krun.cpp:1441
KRun::setAutoDelete
void setAutoDelete(bool b)
Enables or disabled auto deletion.
Definition: krun.cpp:1407
KJobUiDelegate::showErrorMessage
virtual void showErrorMessage()
QUrl::adjusted
QUrl adjusted(QFlags< QUrl::UrlFormattingOption > options) const
KStartupInfo::createNewStartupId
static QByteArray createNewStartupId()
QLatin1String
QDialogButtonBox::setStandardButtons
void setStandardButtons(QFlags< QDialogButtonBox::StandardButton > buttons)
klocalizedstring.h
QApplication::desktop
QDesktopWidget * desktop()
KService::desktopEntryName
QString desktopEntryName() const
KRun::runApplication
static qint64 runApplication(const KService &service, const QList< QUrl > &urls, QWidget *window, RunFlags flags=RunFlags(), const QString &suggestedFileName=QString(), const QByteArray &asn=QByteArray())
Run an application (known from its .desktop file, i.e.
Definition: krun.cpp:749
QBoxLayout::addStretch
void addStretch(int stretch)
KIO::DesktopExecParser::executablePath
static QString executablePath(const QString &execLine)
Given a full command line (e.g.
Definition: desktopexecparser.cpp:440
KProtocolInfo::isHelperProtocol
static bool isHelperProtocol(const QUrl &url)
Returns whether the protocol can act as a helper protocol.
Definition: kprotocolinfo.cpp:393
KRun::error
void error()
Emitted when the operation had an error.
QFileDevice::close
virtual void close()
KRun::setJob
void setJob(KIO::Job *job)
Sets the job.
Definition: krun.cpp:1489
KRun::timer
KIOWIDGETS_DEPRECATED QTimer & timer()
Returns the timer object.
Definition: krun.cpp:1500
QDialogButtonBox
KRun::setFinished
void setFinished(bool finished)
Marks this &#39;KRun&#39; instance as finished.
Definition: krun.cpp:1481
QSize::height
int height() const
KIO::Job
The base class for all jobs.
Definition: job_base.h:54
KIO::ERR_NO_CONTENT
Action succeeded but no content will follow.
Definition: global.h:226
KRun::init
virtual void init()
All following protected methods are used by subclasses of KRun!
Definition: krun.cpp:930
QVariant::toBool
bool toBool() const
QDialog::showEvent
virtual void showEvent(QShowEvent *event)
QHostInfo::localHostName
QString localHostName()
QIODevice::write
qint64 write(const char *data, qint64 maxSize)
QDialog
KIO::SimpleJob::putOnHold
virtual void putOnHold()
Abort job.
Definition: simplejob.cpp:87
QVariant::isValid
bool isValid() const
QDialogButtonBox::button
QPushButton * button(StandardButton which) const
KIO::mostLocalUrl
KIOCORE_EXPORT StatJob * mostLocalUrl(const QUrl &url, JobFlags flags=DefaultFlags)
Tries to map a local URL for the given URL, using a KIO job.
Definition: statjob.cpp:183
KRun::~KRun
virtual ~KRun()
Destructor.
Definition: krun.cpp:1044
KIO::UDSEntry::UDS_MIME_TYPE
A mime type; the slave should set it if it&#39;s known.
Definition: udsentry.h:222
KIO::stat
KIOCORE_EXPORT StatJob * stat(const QUrl &url, JobFlags flags=DefaultFlags)
Find all details for one file or directory.
Definition: statjob.cpp:177
KIO::DesktopExecParser
Parses the Exec= line from a .desktop file, and process all the &#39;%&#39; placeholders, e...
Definition: desktopexecparser.h:48
KRun::KRun
KRun(const QUrl &url, QWidget *window, bool showProgressInfo=true, const QByteArray &asn=QByteArray())
Definition: krun.cpp:894
KIO::TransferJob
The transfer job pumps data into and/or out of a Slave.
Definition: transferjob.h:38
KRun::setProgressInfo
void setProgressInfo(bool progressInfo)
Sets whether progress information shall be shown.
Definition: krun.cpp:1471
QFile::permissions
virtual Permissions permissions() const
QDesktopServices::openUrl
bool openUrl(const QUrl &url)
KIO::Scheduler::publishSlaveOnHold
static void publishSlaveOnHold()
Send the slave that was put on hold back to KLauncher.
Definition: scheduler.cpp:836
KIO::StatJob::statResult
const UDSEntry & statResult() const
Result of the stat operation.
Definition: statjob.cpp:93
QByteArray::size
int size() const
QObject::connect
QMetaObject::Connection connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
QPlainTextEdit::setPlainText
void setPlainText(const QString &text)
KStartupInfoData::setDesktop
void setDesktop(int desktop)
QLabel
KStartupInfoId::initId
void initId(const QByteArray &id="")
QMimeType::name
QString name() const
QPushButton::setDefault
void setDefault(bool)
QVariant::toString
QString toString() const
KConfigGroup::readEntry
T readEntry(const QString &key, const T &aDefault) const
KSycocaEntry::name
QString name() const
QGuiApplication::platformName
QString platformName()
KStartupInfoData::addPid
void addPid(pid_t pid)
KJob
KRun::binaryName
static QString binaryName(const QString &execLine, bool removePath)
Given a full command line (e.g.
Definition: krun.cpp:301
QList::begin
iterator begin()
KRun::shellQuote
static KIOWIDGETS_DEPRECATED void shellQuote(QString &str)
Quotes a string for the shell.
Definition: krun.cpp:281
KRun::setShowScriptExecutionPrompt
void setShowScriptExecutionPrompt(bool showPrompt)
Sets whether a prompt should be shown before executing scripts or desktop files.
Definition: krun.cpp:1436
KIO::DesktopExecParser::hasSchemeHandler
static bool hasSchemeHandler(const QUrl &url)
Returns true if protocol should be opened by a "handler" application, i.e.
Definition: desktopexecparser.cpp:211
QUrl::fromLocalFile
QUrl fromLocalFile(const QString &localFile)
KMessageBox::sorry
void sorry(QWidget *parent, const QString &text, const QString &caption=QString(), Options options=Notify)
KOpenWithDialog::service
KService::Ptr service() const
Definition: kopenwithdialog.cpp:1029
QBoxLayout::addLayout
void addLayout(QLayout *layout, int stretch)
KIO::DesktopExecParser::executableName
static QString executableName(const QString &execLine)
Given a full command line (e.g.
Definition: desktopexecparser.cpp:433
KStartupInfoData::setLaunchedBy
void setLaunchedBy(WId window)
KUrlAuthorized::authorizeUrlAction
bool authorizeUrlAction(const QString &action, const QUrl &baseURL, const QUrl &destURL)
Returns whether a certain URL related action is authorized.
Definition: kurlauthorized.cpp:37
KJob::error
int error() const
KService::serviceByStorageId
static Ptr serviceByStorageId(const QString &_storageId)
KRun::runCommand
static bool runCommand(const QString &cmd, QWidget *window, const QString &workingDirectory=QString())
Run the given shell command and notifies KDE of the starting of the application.
Definition: krun.cpp:855
KRun::hasFinished
bool hasFinished() const
Returns true if the KRun instance has finished.
Definition: krun.cpp:1397
QSaveFile::setFileName
void setFileName(const QString &name)
QUrl::isLocalFile
bool isLocalFile() const
This file is part of the KDE documentation.
Documentation copyright © 1996-2018 The KDE developers.
Generated on Sat Jan 6 2018 05:28:35 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal