KIO

openurljob.cpp
1/*
2 This file is part of the KDE libraries
3 SPDX-FileCopyrightText: 2020 David Faure <faure@kde.org>
4 SPDX-FileCopyrightText: 2022 Harald Sitter <sitter@kde.org>
5
6 SPDX-License-Identifier: LGPL-2.0-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
7*/
8
9#include "openurljob.h"
10#include "commandlauncherjob.h"
11#include "desktopexecparser.h"
12#include "global.h"
13#include "job.h" // for buildErrorString
14#include "jobuidelegatefactory.h"
15#include "kiogui_debug.h"
16#include "openorexecutefileinterface.h"
17#include "openwithhandlerinterface.h"
18#include "untrustedprogramhandlerinterface.h"
19
20#include <KApplicationTrader>
21#include <KAuthorized>
22#include <KConfigGroup>
23#include <KDesktopFile>
24#include <KLocalizedString>
25#include <KSandbox>
26#include <KUrlAuthorized>
27#include <QFileInfo>
28
29#include <KProtocolManager>
30#include <KSharedConfig>
31#include <QDesktopServices>
32#include <QHostInfo>
33#include <QMimeDatabase>
34#include <QOperatingSystemVersion>
35#include <mimetypefinderjob.h>
36
37// For unit test purposes, to test both code paths in externalBrowser()
38KIOGUI_EXPORT bool openurljob_force_use_browserapp_kdeglobals = false;
39
40class KIO::OpenUrlJobPrivate
41{
42public:
43 explicit OpenUrlJobPrivate(const QUrl &url, OpenUrlJob *qq)
44 : m_url(url)
45 , q(qq)
46 {
47 q->setCapabilities(KJob::Killable);
48 }
49
50 void emitAccessDenied();
51 void runUrlWithMimeType();
52 QString externalBrowser() const;
53 bool runExternalBrowser(const QString &exe);
54 void useSchemeHandler();
55
56 QUrl m_url;
57 KIO::OpenUrlJob *const q;
58 QString m_suggestedFileName;
59 QByteArray m_startupId;
60 QString m_mimeTypeName;
61 KService::Ptr m_preferredService;
62 bool m_deleteTemporaryFile = false;
63 bool m_runExecutables = false;
64 bool m_showOpenOrExecuteDialog = false;
65 bool m_externalBrowserEnabled = true;
66 bool m_followRedirections = true;
67
68private:
69 void executeCommand();
70 void handleBinaries(const QMimeType &mimeType);
71 void handleBinariesHelper(const QString &localPath, bool isNativeBinary);
72 void handleDesktopFiles();
73 void handleScripts();
74 void openInPreferredApp();
75 void runLink(const QString &filePath, const QString &urlStr, const QString &optionalServiceName);
76
77 void showOpenWithDialog();
78 void showOpenOrExecuteFileDialog(std::function<void(bool)> dialogFinished);
79 void showUntrustedProgramWarningDialog(const QString &filePath);
80
81 void startService(const KService::Ptr &service, const QList<QUrl> &urls);
82 void startService(const KService::Ptr &service)
83 {
84 startService(service, {m_url});
85 }
86};
87
90 , d(new OpenUrlJobPrivate(url, this))
91{
92}
93
96 , d(new OpenUrlJobPrivate(url, this))
97{
98 d->m_mimeTypeName = mimeType;
99}
100
104
106{
107 return d->m_url;
108}
109
111{
112 d->m_deleteTemporaryFile = b;
113}
114
115void KIO::OpenUrlJob::setSuggestedFileName(const QString &suggestedFileName)
116{
117 d->m_suggestedFileName = suggestedFileName;
118}
119
121{
122 d->m_startupId = startupId;
123}
124
126{
127 d->m_runExecutables = allow;
128}
129
131{
132 d->m_showOpenOrExecuteDialog = b;
133}
134
136{
137 d->m_externalBrowserEnabled = b;
138}
139
141{
142 d->m_followRedirections = b;
143}
144
146{
147 if (!d->m_url.isValid() || d->m_url.scheme().isEmpty()) {
148 const QString error = !d->m_url.isValid() ? d->m_url.errorString() : d->m_url.toDisplayString();
149 setError(KIO::ERR_MALFORMED_URL);
150 setErrorText(i18n("Malformed URL\n%1", error));
151 emitResult();
152 return;
153 }
154 if (!KUrlAuthorized::authorizeUrlAction(QStringLiteral("open"), QUrl(), d->m_url)) {
155 d->emitAccessDenied();
156 return;
157 }
158
159 auto qtOpenUrl = [this]() {
160 if (!QDesktopServices::openUrl(d->m_url)) {
161 // Is this an actual error, or USER_CANCELED?
162 setError(KJob::UserDefinedError);
163 setErrorText(i18n("Failed to open %1", d->m_url.toDisplayString()));
164 }
165 emitResult();
166 };
167
168#if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
169 if (d->m_externalBrowserEnabled) {
170 // For Windows and MacOS, the mimetypes handling is different, so use QDesktopServices
171 qtOpenUrl();
172 return;
173 }
174#endif
175
176 if (d->m_externalBrowserEnabled && KSandbox::isInside()) {
177 // Use the function from QDesktopServices as it handles portals correctly
178 // Note that it falls back to "normal way" if the portal service isn't running.
179 qtOpenUrl();
180 return;
181 }
182
183 // If we know the MIME type, proceed
184 if (!d->m_mimeTypeName.isEmpty()) {
185 d->runUrlWithMimeType();
186 return;
187 }
188
189 if (d->m_url.scheme().startsWith(QLatin1String("http"))) {
190 if (d->m_externalBrowserEnabled) {
191 const QString externalBrowser = d->externalBrowser();
192 if (!externalBrowser.isEmpty() && d->runExternalBrowser(externalBrowser)) {
193 return;
194 }
195 }
196 } else {
198 d->useSchemeHandler();
199 return;
200 }
201 }
202
203 auto *job = new KIO::MimeTypeFinderJob(d->m_url, this);
204 job->setFollowRedirections(d->m_followRedirections);
205 job->setSuggestedFileName(d->m_suggestedFileName);
206 connect(job, &KJob::result, this, [job, this]() {
207 const int errCode = job->error();
208 if (errCode) {
209 setError(errCode);
210 setErrorText(job->errorText());
211 emitResult();
212 } else {
213 d->m_suggestedFileName = job->suggestedFileName();
214 d->m_mimeTypeName = job->mimeType();
215 d->runUrlWithMimeType();
216 }
217 });
218 job->start();
219}
220
221bool KIO::OpenUrlJob::doKill()
222{
223 return true;
224}
225
226QString KIO::OpenUrlJobPrivate::externalBrowser() const
227{
228 if (!m_externalBrowserEnabled) {
229 return QString();
230 }
231
232 if (!openurljob_force_use_browserapp_kdeglobals) {
233 KService::Ptr externalBrowser = KApplicationTrader::preferredService(QStringLiteral("x-scheme-handler/https"));
234 if (!externalBrowser) {
235 externalBrowser = KApplicationTrader::preferredService(QStringLiteral("x-scheme-handler/http"));
236 }
237 if (externalBrowser) {
238 return externalBrowser->storageId();
239 }
240 }
241
242 const QString browserApp = KConfigGroup(KSharedConfig::openConfig(), QStringLiteral("General")).readEntry("BrowserApplication");
243 return browserApp;
244}
245
246bool KIO::OpenUrlJobPrivate::runExternalBrowser(const QString &exec)
247{
248 if (exec.startsWith(QLatin1Char('!'))) {
249 // Literal command
250 const QString command = QStringView(exec).mid(1) + QLatin1String(" %u");
251 KService::Ptr service(new KService(QString(), command, QString()));
252 startService(service);
253 return true;
254 } else {
255 // Name of desktop file
257 if (service) {
258 startService(service);
259 return true;
260 }
261 }
262 return false;
263}
264
265void KIO::OpenUrlJobPrivate::useSchemeHandler()
266{
267 // look for an application associated with x-scheme-handler/<protocol>
268 const KService::Ptr service = KApplicationTrader::preferredService(QLatin1String("x-scheme-handler/") + m_url.scheme());
269 if (service) {
270 startService(service);
271 return;
272 }
273 // fallback, look for associated helper protocol
274 Q_ASSERT(KProtocolInfo::isHelperProtocol(m_url.scheme()));
275 const auto exec = KProtocolInfo::exec(m_url.scheme());
276 if (exec.isEmpty()) {
277 // use default MIME type opener for file
278 m_mimeTypeName = KProtocolManager::defaultMimetype(m_url);
279 runUrlWithMimeType();
280 } else {
281 KService::Ptr servicePtr(new KService(QString(), exec, QString()));
282 startService(servicePtr);
283 }
284}
285
286void KIO::OpenUrlJobPrivate::startService(const KService::Ptr &service, const QList<QUrl> &urls)
287{
288 KIO::ApplicationLauncherJob *job = new KIO::ApplicationLauncherJob(service, q);
289 job->setUrls(urls);
291 job->setSuggestedFileName(m_suggestedFileName);
292 job->setStartupId(m_startupId);
293 q->addSubjob(job);
294 job->start();
295}
296
297void KIO::OpenUrlJobPrivate::runLink(const QString &filePath, const QString &urlStr, const QString &optionalServiceName)
298{
299 if (urlStr.isEmpty()) {
300 q->setError(KJob::UserDefinedError);
301 q->setErrorText(i18n("The desktop entry file\n%1\nis of type Link but has no URL=... entry.", filePath));
302 q->emitResult();
303 return;
304 }
305
306 m_url = QUrl::fromUserInput(urlStr);
307 m_mimeTypeName.clear();
308
309 // X-KDE-LastOpenedWith holds the service desktop entry name that
310 // should be preferred for opening this URL if possible.
311 // This is used by the Recent Documents menu for instance.
312 if (!optionalServiceName.isEmpty()) {
313 m_preferredService = KService::serviceByDesktopName(optionalServiceName);
314 }
315
316 // Restart from scratch with the target of the link
317 q->start();
318}
319
320void KIO::OpenUrlJobPrivate::emitAccessDenied()
321{
322 q->setError(KIO::ERR_ACCESS_DENIED);
323 q->setErrorText(KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, m_url.toDisplayString()));
324 q->emitResult();
325}
326
327// was: KRun::isExecutable (minus application/x-desktop MIME type).
328// Feel free to make public if needed.
329static bool isBinary(const QMimeType &mimeType)
330{
331 // - Binaries could be e.g.:
332 // - application/x-executable
333 // - application/x-sharedlib e.g. /usr/bin/ls, see
334 // https://gitlab.freedesktop.org/xdg/shared-mime-info/-/issues/11
335 //
336 // - MIME types that inherit application/x-executable _and_ text/plain are scripts, these are
337 // handled by handleScripts()
338
339 return (mimeType.inherits(QStringLiteral("application/x-executable")) || mimeType.inherits(QStringLiteral("application/x-ms-dos-executable")));
340}
341
342// Helper function that returns whether a file is a text-based script
343// e.g. ".sh", ".csh", ".py", ".js"
344static bool isTextScript(const QMimeType &mimeType)
345{
346 return (mimeType.inherits(QStringLiteral("application/x-executable")) && mimeType.inherits(QStringLiteral("text/plain")));
347}
348
349// Helper function that returns whether a file has the execute bit set or not.
350static bool hasExecuteBit(const QString &fileName)
351{
352 return QFileInfo(fileName).isExecutable();
353}
354
355bool KIO::OpenUrlJob::isExecutableFile(const QUrl &url, const QString &mimetypeString)
356{
357 if (!url.isLocalFile()) {
358 return false;
359 }
360
361 QMimeDatabase db;
362 QMimeType mimeType = db.mimeTypeForName(mimetypeString);
363 return (isBinary(mimeType) || isTextScript(mimeType)) && hasExecuteBit(url.toLocalFile());
364}
365
366// Handle native binaries (.e.g. /usr/bin/*); and .exe files
367void KIO::OpenUrlJobPrivate::handleBinaries(const QMimeType &mimeType)
368{
369 if (!KAuthorized::authorize(KAuthorized::SHELL_ACCESS)) {
370 emitAccessDenied();
371 return;
372 }
373
374 const bool isLocal = m_url.isLocalFile();
375 // Don't run remote executables
376 if (!isLocal) {
377 q->setError(KJob::UserDefinedError);
378 q->setErrorText(
379 i18n("The executable file \"%1\" is located on a remote filesystem. "
380 "For safety reasons it will not be started.",
381 m_url.toDisplayString()));
382 q->emitResult();
383 return;
384 }
385
386 const QString localPath = m_url.toLocalFile();
387
388 bool isNativeBinary = true;
389#ifndef Q_OS_WIN
390 isNativeBinary = !mimeType.inherits(QStringLiteral("application/x-ms-dos-executable"));
391#endif
392
393 if (m_showOpenOrExecuteDialog) {
394 auto dialogFinished = [this, localPath, isNativeBinary](bool shouldExecute) {
395 // shouldExecute is always true if we get here, because for binaries the
396 // dialog only offers Execute/Cancel
397 Q_UNUSED(shouldExecute)
398
399 handleBinariesHelper(localPath, isNativeBinary);
400 };
401
402 // Ask the user for confirmation before executing this binary (for binaries
403 // the dialog will only show Execute/Cancel)
404 showOpenOrExecuteFileDialog(dialogFinished);
405 return;
406 }
407
408 handleBinariesHelper(localPath, isNativeBinary);
409}
410
411void KIO::OpenUrlJobPrivate::handleBinariesHelper(const QString &localPath, bool isNativeBinary)
412{
413 if (!m_runExecutables) {
414 q->setError(KJob::UserDefinedError);
415 q->setErrorText(i18n("For security reasons, launching executables is not allowed in this context."));
416 q->emitResult();
417 return;
418 }
419
420 // For local .exe files, open in the default app (e.g. WINE)
421 if (!isNativeBinary) {
422 openInPreferredApp();
423 return;
424 }
425
426 // Native binaries
427 if (!hasExecuteBit(localPath)) {
428 // Show untrustedProgram dialog for local, native executables without the execute bit
429 showUntrustedProgramWarningDialog(localPath);
430 return;
431 }
432
433 // Local executable with execute bit, proceed
434 executeCommand();
435}
436
437// For local, native executables (i.e. not shell scripts) without execute bit,
438// show a prompt asking the user if he wants to run the program.
439void KIO::OpenUrlJobPrivate::showUntrustedProgramWarningDialog(const QString &filePath)
440{
442 if (!untrustedProgramHandler) {
443 // No way to ask the user to make it executable
444 q->setError(KJob::UserDefinedError);
445 q->setErrorText(i18n("The program \"%1\" needs to have executable permission before it can be launched.", filePath));
446 q->emitResult();
447 return;
448 }
449 QObject::connect(untrustedProgramHandler, &KIO::UntrustedProgramHandlerInterface::result, q, [=, this](bool result) {
450 if (result) {
451 QString errorString;
452 if (untrustedProgramHandler->setExecuteBit(filePath, errorString)) {
453 executeCommand();
454 } else {
455 q->setError(KJob::UserDefinedError);
456 q->setErrorText(i18n("Unable to make file \"%1\" executable.\n%2.", filePath, errorString));
457 q->emitResult();
458 }
459 } else {
460 q->setError(KIO::ERR_USER_CANCELED);
461 q->emitResult();
462 }
463 });
464 untrustedProgramHandler->showUntrustedProgramWarning(q, m_url.fileName());
465}
466
467void KIO::OpenUrlJobPrivate::executeCommand()
468{
469 // Execute the URL as a command. This is how we start scripts and executables
470 KIO::CommandLauncherJob *job = new KIO::CommandLauncherJob(m_url.toLocalFile(), QStringList());
471 job->setStartupId(m_startupId);
473 q->addSubjob(job);
474 job->start();
475
476 // TODO implement deleting the file if tempFile==true
477 // CommandLauncherJob doesn't support that, unlike ApplicationLauncherJob
478 // We'd have to do it in KProcessRunner.
479}
480
481void KIO::OpenUrlJobPrivate::runUrlWithMimeType()
482{
483 // Tell the app, in case it wants us to stop here
484 Q_EMIT q->mimeTypeFound(m_mimeTypeName);
485 if (q->error() == KJob::KilledJobError) {
486 q->emitResult();
487 return;
488 }
489
490 // Support for preferred service setting, see setPreferredService
491 if (m_preferredService && m_preferredService->hasMimeType(m_mimeTypeName)) {
492 startService(m_preferredService);
493 return;
494 }
495
496 // Scripts and executables
497 QMimeDatabase db;
498 const QMimeType mimeType = db.mimeTypeForName(m_mimeTypeName);
499
500 // .desktop files
501 if (mimeType.inherits(QStringLiteral("application/x-desktop"))) {
502 handleDesktopFiles();
503 return;
504 }
505
506 // Scripts (e.g. .sh, .csh, .py, .js)
507 if (isTextScript(mimeType)) {
508 handleScripts();
509 return;
510 }
511
512 // Binaries (e.g. /usr/bin/{konsole,ls}) and .exe files
513 if (isBinary(mimeType)) {
514 handleBinaries(mimeType);
515 return;
516 }
517
518 // General case: look up associated application
519 openInPreferredApp();
520}
521
522void KIO::OpenUrlJobPrivate::handleDesktopFiles()
523{
524 // Open remote .desktop files in the default (text editor) app
525 if (!m_url.isLocalFile()) {
526 openInPreferredApp();
527 return;
528 }
529
530 if (m_url.fileName() == QLatin1String(".directory") || m_mimeTypeName == QLatin1String("application/x-theme")) {
531 // We cannot execute these files, open in the default app
532 m_mimeTypeName = QStringLiteral("text/plain");
533 openInPreferredApp();
534 return;
535 }
536
537 const QString filePath = m_url.toLocalFile();
538 KDesktopFile cfg(filePath);
539 KConfigGroup cfgGroup = cfg.desktopGroup();
540 if (!cfgGroup.hasKey("Type")) {
541 q->setError(KJob::UserDefinedError);
542 q->setErrorText(i18n("The desktop entry file %1 has no Type=... entry.", filePath));
543 q->emitResult();
544 openInPreferredApp();
545 return;
546 }
547
548 if (cfg.hasLinkType()) {
549 runLink(filePath, cfg.readUrl(), cfg.desktopGroup().readEntry("X-KDE-LastOpenedWith"));
550 return;
551 }
552
553 if ((cfg.hasApplicationType() || cfg.readType() == QLatin1String("Service"))) { // kio_settings lets users run Type=Service desktop files
554 KService::Ptr service(new KService(filePath));
555 if (!service->exec().isEmpty()) {
556 if (m_showOpenOrExecuteDialog) { // Show the openOrExecute dialog
557 auto dialogFinished = [this, filePath, service](bool shouldExecute) {
558 if (shouldExecute) { // Run the file
559 startService(service, {});
560 return;
561 }
562 // The user selected "open"
563 openInPreferredApp();
564 };
565
566 showOpenOrExecuteFileDialog(dialogFinished);
567 return;
568 }
569
570 if (m_runExecutables) {
571 startService(service, {});
572 return;
573 }
574 } // exec is not empty
575 } // type Application or Service
576
577 // Fallback to opening in the default app
578 openInPreferredApp();
579}
580
581void KIO::OpenUrlJobPrivate::handleScripts()
582{
583 // Executable scripts of any type can run arbitrary shell commands
584 if (!KAuthorized::authorize(KAuthorized::SHELL_ACCESS)) {
585 emitAccessDenied();
586 return;
587 }
588
589 const bool isLocal = m_url.isLocalFile();
590 const QString localPath = m_url.toLocalFile();
591 if (!isLocal || !hasExecuteBit(localPath)) {
592 // Open remote scripts or ones without the execute bit, with the default application
593 openInPreferredApp();
594 return;
595 }
596
597 if (m_showOpenOrExecuteDialog) {
598 auto dialogFinished = [this](bool shouldExecute) {
599 if (shouldExecute) {
600 executeCommand();
601 } else {
602 openInPreferredApp();
603 }
604 };
605
606 showOpenOrExecuteFileDialog(dialogFinished);
607 return;
608 }
609
610 if (m_runExecutables) { // Local executable script, proceed
611 executeCommand();
612 } else { // Open in the default (text editor) app
613 openInPreferredApp();
614 }
615}
616
617void KIO::OpenUrlJobPrivate::openInPreferredApp()
618{
619 KService::Ptr service = KApplicationTrader::preferredService(m_mimeTypeName);
620 if (service) {
621 // If file mimetype is set to xdg-open or kde-open, the file will be opened in endless loop
622 // In these cases, showOpenWithDialog instead
623 const QStringList disallowedWrappers = {QStringLiteral("xdg-open"), QStringLiteral("kde-open")};
624 if (disallowedWrappers.contains(service.data()->exec())) {
625 showOpenWithDialog();
626 return;
627 }
628 startService(service);
629 } else {
630 // Avoid directly opening partial downloads and incomplete files
631 // This is done here in the off chance the user actually has a default handler for it
632 if (m_mimeTypeName == QLatin1String("application/x-partial-download")) {
633 q->setError(KJob::UserDefinedError);
634 q->setErrorText(
635 i18n("This file is incomplete and should not be opened.\n"
636 "Check your open applications and the notification area for any pending tasks or downloads."));
637 q->emitResult();
638 return;
639 }
640
641 showOpenWithDialog();
642 }
643}
644
645void KIO::OpenUrlJobPrivate::showOpenWithDialog()
646{
647 if (!KAuthorized::authorizeAction(QStringLiteral("openwith"))) {
648 q->setError(KJob::UserDefinedError);
649 q->setErrorText(i18n("You are not authorized to select an application to open this file."));
650 q->emitResult();
651 return;
652 }
653
656 // As KDE on windows doesn't know about the windows default applications, offers will be empty in nearly all cases.
657 // So we use QDesktopServices::openUrl to let windows decide how to open the file.
658 // It's also our fallback if there's no handler to show an open-with dialog.
659 if (!QDesktopServices::openUrl(m_url)) {
660 q->setError(KJob::UserDefinedError);
661 q->setErrorText(i18n("Failed to open the file."));
662 }
663 q->emitResult();
664 return;
665 }
666
667 QObject::connect(openWithHandler, &KIO::OpenWithHandlerInterface::canceled, q, [this]() {
668 q->setError(KIO::ERR_USER_CANCELED);
669 q->emitResult();
670 });
671
672 QObject::connect(openWithHandler, &KIO::OpenWithHandlerInterface::serviceSelected, q, [this](const KService::Ptr &service) {
673 startService(service);
674 });
675
676 QObject::connect(openWithHandler, &KIO::OpenWithHandlerInterface::handled, q, [this]() {
677 q->emitResult();
678 });
679
680 openWithHandler->promptUserForApplication(q, {m_url}, m_mimeTypeName);
681}
682
683void KIO::OpenUrlJobPrivate::showOpenOrExecuteFileDialog(std::function<void(bool)> dialogFinished)
684{
685 QMimeDatabase db;
686 QMimeType mimeType = db.mimeTypeForName(m_mimeTypeName);
687
688 auto *openOrExecuteFileHandler = KIO::delegateExtension<KIO::OpenOrExecuteFileInterface *>(q);
689 if (!openOrExecuteFileHandler) {
690 // No way to ask the user whether to execute or open
691 if (isTextScript(mimeType) || mimeType.inherits(QStringLiteral("application/x-desktop"))) { // Open text-based ones in the default app
692 openInPreferredApp();
693 } else {
694 q->setError(KJob::UserDefinedError);
695 q->setErrorText(i18n("The program \"%1\" could not be launched.", m_url.toDisplayString(QUrl::PreferLocalFile)));
696 q->emitResult();
697 }
698 return;
699 }
700
701 QObject::connect(openOrExecuteFileHandler, &KIO::OpenOrExecuteFileInterface::canceled, q, [this]() {
702 q->setError(KIO::ERR_USER_CANCELED);
703 q->emitResult();
704 });
705
706 QObject::connect(openOrExecuteFileHandler, &KIO::OpenOrExecuteFileInterface::executeFile, q, [this, dialogFinished](bool shouldExecute) {
707 m_runExecutables = shouldExecute;
708 dialogFinished(shouldExecute);
709 });
710
711 openOrExecuteFileHandler->promptUserOpenOrExecute(q, m_mimeTypeName);
712}
713
714void KIO::OpenUrlJob::slotResult(KJob *job)
715{
716 // This is only used for the final application/launcher job, so we're done when it's done
717 const int errCode = job->error();
718 if (errCode) {
719 setError(errCode);
720 // We're a KJob, not a KIO::Job, so build the error string here
721 setErrorText(KIO::buildErrorString(errCode, job->errorText()));
722 }
723 emitResult();
724}
725
726#include "moc_openurljob.cpp"
static Q_INVOKABLE bool authorize(const QString &action)
static Q_INVOKABLE bool authorizeAction(const QString &action)
virtual bool addSubjob(KJob *job)
KCompositeJob(QObject *parent=nullptr)
bool hasKey(const char *key) const
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...
@ DeleteTemporaryFiles
the URLs passed to the service will be deleted when it exits (if the URLs are local files)
void setRunFlags(RunFlags runFlags)
Specifies various flags.
QFlags< RunFlag > RunFlags
Stores a combination of RunFlag values.
void setStartupId(const QByteArray &startupId)
Sets the platform-specific startup id of the application launch.
void start() override
Starts the job.
void setUrls(const QList< QUrl > &urls)
Specifies the URLs to be passed to the application.
void setWorkingDirectory(const QString &workingDirectory)
Sets the working directory from which to run the command.
void start() override
Starts the job.
void setStartupId(const QByteArray &startupId)
Sets the platform-specific startup id of the command launch.
static bool hasSchemeHandler(const QUrl &url)
Returns true if protocol should be opened by a "handler" application, i.e. an application associated ...
MimeTypeFinderJob finds out the MIME type of a URL.
void executeFile(bool enable)
Emitted by promptUserOpenOrExecute() once the user chooses an action.
void canceled()
Emitted by promptUserOpenOrExecute() if user selects cancel.
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 it to a...
void setDeleteTemporaryFile(bool b)
Specifies that the URL passed to the application will be deleted when it exits (if the URL is a local...
void start() override
Starts the job.
void setEnableExternalBrowser(bool b)
Sets whether the external webbrowser setting should be honoured.
void setFollowRedirections(bool b)
Sets whether the job should follow URL redirections.
void setRunExecutables(bool allow)
Set this to true if this class should allow the user to run executables.
void mimeTypeFound(const QString &mimeType)
Emitted when the MIME type is determined.
OpenUrlJob(const QUrl &url, QObject *parent=nullptr)
Creates an OpenUrlJob in order to open a URL.
static bool isExecutableFile(const QUrl &url, const QString &mimetypeName)
Returns whether the url of mimetype is executable.
~OpenUrlJob() override
Destructor.
QUrl url() const
Returns the URL the OpenUrlJob was created with.
void setShowOpenOrExecuteDialog(bool b)
Set this to true if this class should show a dialog to ask the user about how to handle various types...
void setStartupId(const QByteArray &startupId)
Sets the platform-specific startup id of the application launch.
void serviceSelected(const KService::Ptr &service)
Emitted by promptUserForApplication() once the user chooses an application.
void handled()
Emitted by promptUserForApplication() if it fully handled it including launching the app.
void canceled()
Emitted by promptUserForApplication() if the user canceled the application selection dialog.
void result(bool confirmed)
Implementations of this interface must emit result in showUntrustedProgramWarning.
void setErrorText(const QString &errorText)
void emitResult()
int error() const
void result(KJob *job)
void setError(int errorCode)
QString errorText() const
static QString exec(const QString &protocol)
Returns the library / executable to open for the protocol protocol Example : "kio_ftp",...
static bool isHelperProtocol(const QUrl &url)
Returns whether the protocol can act as a helper protocol.
static QString defaultMimetype(const QUrl &url)
Returns default MIME type for this URL based on the protocol.
static Ptr serviceByStorageId(const QString &_storageId)
QString storageId() const
static Ptr serviceByDesktopName(const QString &_name)
QString exec() const
QExplicitlySharedDataPointer< KService > Ptr
bool hasMimeType(const QString &mimeType) const
static KSharedConfig::Ptr openConfig(const QString &fileName=QString(), OpenFlags mode=FullConfig, QStandardPaths::StandardLocation type=QStandardPaths::GenericConfigLocation)
QString i18n(const char *text, const TYPE &arg...)
KSERVICE_EXPORT KService::Ptr preferredService(const QString &mimeType)
KCALUTILS_EXPORT QString mimeType()
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:31
T delegateExtension(KJob *job)
Returns the child of the job's uiDelegate() that implements the given extension, or nullptr if none w...
KCOREADDONS_EXPORT bool isInside()
bool authorizeUrlAction(const QString &action, const QUrl &baseURL, const QUrl &destURL)
Returns whether a certain URL related action is authorized.
OKULARCORE_EXPORT QString errorString(SigningResult result, const QVariant &additionalMessage)
bool openUrl(const QUrl &url)
QMimeType mimeTypeForName(const QString &nameOrAlias) const const
QObject(QObject *parent)
QMetaObject::Connection connect(const QObject *sender, PointerToMemberFunction signal, Functor functor)
QObject * parent() const const
void clear()
bool isEmpty() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
bool contains(QLatin1StringView str, Qt::CaseSensitivity cs) const const
RemoveFilename
QUrl adjusted(FormattingOptions options) const const
QString fileName(ComponentFormattingOptions options) const const
QUrl fromUserInput(const QString &userInput, const QString &workingDirectory, UserInputResolutionOptions options)
bool isLocalFile() const const
QString scheme() const const
QString toDisplayString(FormattingOptions options) const const
QString toLocalFile() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2025 The KDE developers.
Generated on Fri May 2 2025 12:02:24 by doxygen 1.13.2 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.