Changeset View
Standalone View
src/widgets/krun.cpp
Show First 20 Lines • Show All 51 Lines • ▼ Show 20 Line(s) | |||||
52 | #include <kjobuidelegate.h> | 52 | #include <kjobuidelegate.h> | ||
53 | #include <kmimetypetrader.h> | 53 | #include <kmimetypetrader.h> | ||
54 | #include "kio/job.h" | 54 | #include "kio/job.h" | ||
55 | #include "kio/global.h" | 55 | #include "kio/global.h" | ||
56 | #include "kio/scheduler.h" | 56 | #include "kio/scheduler.h" | ||
57 | #include "kopenwithdialog.h" | 57 | #include "kopenwithdialog.h" | ||
58 | #include "krecentdocument.h" | 58 | #include "krecentdocument.h" | ||
59 | #include "kdesktopfileactions.h" | 59 | #include "kdesktopfileactions.h" | ||
60 | #include "kfileitem.h" | ||||
60 | #include "executablefileopendialog_p.h" | 61 | #include "executablefileopendialog_p.h" | ||
61 | #include <kio/desktopexecparser.h> | 62 | #include <kio/desktopexecparser.h> | ||
62 | 63 | | |||
63 | #include <kurlauthorized.h> | 64 | #include <kurlauthorized.h> | ||
64 | #include <kmessagebox.h> | 65 | #include <kmessagebox.h> | ||
65 | #include <ktoolinvocation.h> | 66 | #include <ktoolinvocation.h> | ||
66 | #include <klocalizedstring.h> | 67 | #include <klocalizedstring.h> | ||
67 | #include <kprotocolmanager.h> | 68 | #include <kprotocolmanager.h> | ||
▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Line(s) | 127 | return !QStandardPaths::locate(QStandardPaths::RuntimeLocation, | |||
127 | QLatin1String("flatpak-info")).isEmpty() || | 128 | QLatin1String("flatpak-info")).isEmpty() || | ||
128 | qEnvironmentVariableIsSet("SNAP"); | 129 | qEnvironmentVariableIsSet("SNAP"); | ||
129 | } | 130 | } | ||
130 | 131 | | |||
131 | // --------------------------------------------------------------------------- | 132 | // --------------------------------------------------------------------------- | ||
132 | 133 | | |||
133 | bool KRun::isExecutableFile(const QUrl &url, const QString &mimetype) | 134 | bool KRun::isExecutableFile(const QUrl &url, const QString &mimetype) | ||
134 | { | 135 | { | ||
136 | //File not local | ||||
135 | if (!url.isLocalFile()) { | 137 | if (!url.isLocalFile()) { | ||
136 | return false; | 138 | return false; | ||
137 | } | 139 | } | ||
138 | QFileInfo file(url.toLocalFile()); | 140 | QFileInfo file(url.toLocalFile()); | ||
139 | if (file.isExecutable()) { // Got a prospective file to run | 141 | //File not marked as executable | ||
dfaure: I wonder why this doesn't use isExecutable(mimetype)... | |||||
Hmm, because isExecutable(mimetype) also returns true for desktop files. So this would change behaviour for users of this API. (see why we try to limit public API...). Most users found in https://lxr.kde.org/ident?_i=isExecutableFile would actually see this as a bugfix (they warn about, or forbid, local execution), but So... I was just wondering (and hinting at an investigation, not requesting a change), but I have my answer now.. I suggest to revert your last change, and maybe add a comment about why we can't use isExecutable. (Or we could extract a common function...) dfaure: Hmm, because isExecutable(mimetype) also returns true for desktop files.
So this would change… | |||||
I understand, it was a bit careless from me not to check this beforehand. Reverted and added a note. mdlubakowski: I understand, it was a bit careless from me not to check this beforehand. Reverted and added a… | |||||
140 | QMimeDatabase db; | 142 | if (!file.isExecutable()) { | ||
141 | QMimeType mimeType = db.mimeTypeForName(mimetype); | 143 | return false; | ||
142 | if (mimeType.inherits(QStringLiteral("application/x-executable")) || | | |||
143 | #ifdef Q_OS_WIN | | |||
144 | mimeType.inherits(QStringLiteral("application/x-ms-dos-executable")) || | | |||
145 | #endif | | |||
146 | mimeType.inherits(QStringLiteral("application/x-executable-script")) || | | |||
147 | mimeType.inherits(QStringLiteral("application/x-sharedlib")) | | |||
148 | ) { | | |||
149 | return true; | | |||
150 | } | | |||
151 | } | 144 | } | ||
145 | //File does not have correct mimetype | ||||
146 | if (!isExecutable(mimetype)) { | ||||
152 | return false; | 147 | return false; | ||
153 | } | 148 | } | ||
149 | return true; | ||||
150 | } | ||||
154 | 151 | | |||
155 | void KRun::handleInitError(int kioErrorCode, const QString &errorMsg) | 152 | void KRun::handleInitError(int kioErrorCode, const QString &errorMsg) | ||
please make this function as file static, so there is no need to expose it as API of the KRun class pino: please make this function as file static, so there is no need to expose it as API of the KRun… | |||||
156 | { | 153 | { | ||
157 | Q_UNUSED(kioErrorCode); | 154 | Q_UNUSED(kioErrorCode); | ||
158 | d->m_showingDialog = true; | 155 | d->m_showingDialog = true; | ||
dfaure: This could now be simplified to `return file.isExecutable();` | |||||
159 | KMessageBox::error(d->m_window, errorMsg); | 156 | KMessageBox::error(d->m_window, errorMsg); | ||
160 | d->m_showingDialog = false; | 157 | d->m_showingDialog = false; | ||
161 | } | 158 | } | ||
162 | 159 | | |||
163 | void KRun::handleError(KJob *job) | 160 | void KRun::handleError(KJob *job) | ||
164 | { | 161 | { | ||
165 | Q_ASSERT(job); | 162 | Q_ASSERT(job); | ||
166 | if (job) { | 163 | if (job) { | ||
Show All 14 Lines | 172 | { | |||
181 | return runUrl(url, mimetype, window, flags, suggestedFileName, asn); | 178 | return runUrl(url, mimetype, window, flags, suggestedFileName, asn); | ||
182 | } | 179 | } | ||
183 | #endif | 180 | #endif | ||
184 | 181 | | |||
185 | // This is called by foundMimeType, since it knows the mimetype of the URL | 182 | // This is called by foundMimeType, since it knows the mimetype of the URL | ||
186 | bool KRun::runUrl(const QUrl &u, const QString &_mimetype, QWidget *window, RunFlags flags, const QString &suggestedFileName, const QByteArray &asn) | 183 | bool KRun::runUrl(const QUrl &u, const QString &_mimetype, QWidget *window, RunFlags flags, const QString &suggestedFileName, const QByteArray &asn) | ||
187 | { | 184 | { | ||
188 | const bool runExecutables = flags.testFlag(KRun::RunExecutables); | 185 | const bool runExecutables = flags.testFlag(KRun::RunExecutables); | ||
189 | const bool tempFile = flags.testFlag(KRun::DeleteTemporaryFiles); | 186 | const bool tempFile = flags.testFlag(KRun::DeleteTemporaryFiles); | ||
_pre-existing) this code will also be triggered when switching virtual desktops, and we don't want a resize then. So this should test for e->spontaneous() and return early if true. dfaure: _pre-existing) this code will also be triggered when switching virtual desktops, and we don't… | |||||
190 | bool noRun = false; | 187 | bool noRun = false; | ||
191 | bool noAuth = false; | 188 | bool noAuth = false; | ||
192 | if (_mimetype == QLatin1String("inode/directory-locked")) { | 189 | if (_mimetype == QLatin1String("inode/directory-locked")) { | ||
193 | KMessageBox::error(window, | 190 | KMessageBox::error(window, | ||
194 | i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", u.toDisplayString().toHtmlEscaped())); | 191 | i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", u.toDisplayString().toHtmlEscaped())); | ||
195 | return false; | 192 | return false; | ||
196 | } else if (_mimetype == QLatin1String("application/x-desktop")) { | 193 | } else if (_mimetype == QLatin1String("application/x-desktop")) { | ||
197 | if (u.isLocalFile() && runExecutables) { | 194 | if (u.isLocalFile() && runExecutables) { | ||
198 | return KDesktopFileActions::runWithStartup(u, true, asn); | 195 | return KDesktopFileActions::runWithStartup(u, true, asn); | ||
199 | } | 196 | } | ||
200 | } else if (isExecutableFile(u, _mimetype)) { | 197 | } else if (isExecutableFile(u, _mimetype)) { | ||
201 | if (u.isLocalFile() && runExecutables) { | 198 | if (u.isLocalFile() && runExecutables) { | ||
202 | if (KAuthorized::authorize(QStringLiteral("shell_access"))) { | 199 | if (KAuthorized::authorize(QStringLiteral("shell_access"))) { | ||
203 | return (KRun::runCommand(KShell::quoteArg(u.toLocalFile()), QString(), QString(), | 200 | return (KRun::runCommand(KShell::quoteArg(u.toLocalFile()), QString(), QString(), | ||
204 | window, asn, u.adjusted(QUrl::RemoveFilename).toLocalFile())); // just execute the url as a command | 201 | window, asn, u.adjusted(QUrl::RemoveFilename).toLocalFile())); // just execute the url as a command | ||
205 | // ## TODO implement deleting the file if tempFile==true | 202 | // ## TODO implement deleting the file if tempFile==true | ||
206 | } else { | 203 | } else { | ||
207 | noAuth = true; | 204 | noAuth = true; | ||
At this point checking the mimetype again is redundant, it was done on line 328. I guess we need a simple QFileInfo::isExecutable call or wrapper. dfaure: At this point checking the mimetype again is redundant, it was done on line 328. I guess we… | |||||
208 | } | 205 | } | ||
209 | } else if (_mimetype == QLatin1String("application/x-executable")) { | 206 | } else if (_mimetype == QLatin1String("application/x-executable")) { | ||
210 | noRun = true; | 207 | noRun = true; | ||
211 | } | 208 | } | ||
212 | } else if (isExecutable(_mimetype)) { | 209 | } else if (isExecutable(_mimetype)) { | ||
213 | if (!runExecutables) { | 210 | if (!runExecutables) { | ||
214 | noRun = true; | 211 | noRun = true; | ||
215 | } | 212 | } | ||
216 | 213 | | |||
217 | if (!KAuthorized::authorize(QStringLiteral("shell_access"))) { | 214 | if (!KAuthorized::authorize(QStringLiteral("shell_access"))) { | ||
218 | noAuth = true; | 215 | noAuth = true; | ||
... here this dialog can show the error to the user (also, please drop the exclamation mark from the message) pino: ... here this dialog can show the error to the user
(also, please drop the exclamation mark… | |||||
219 | } | 216 | } | ||
220 | } | 217 | } | ||
221 | 218 | | |||
dfaure: Is this line necessary? (I wouldn't think so) | |||||
222 | if (noRun) { | 219 | if (noRun) { | ||
223 | KMessageBox::sorry(window, | 220 | KMessageBox::sorry(window, | ||
224 | i18n("<qt>The file <b>%1</b> is an executable program. " | 221 | i18n("<qt>The file <b>%1</b> is an executable program. " | ||
225 | "For safety it will not be started.</qt>", u.toDisplayString().toHtmlEscaped())); | 222 | "For safety it will not be started.</qt>", u.toDisplayString().toHtmlEscaped())); | ||
226 | return false; | 223 | return false; | ||
227 | } | 224 | } | ||
228 | if (noAuth) { | 225 | if (noAuth) { | ||
229 | KMessageBox::error(window, | 226 | KMessageBox::error(window, | ||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Line(s) | |||||
283 | 280 | | |||
284 | #ifndef KIOWIDGETS_NO_DEPRECATED | 281 | #ifndef KIOWIDGETS_NO_DEPRECATED | ||
285 | void KRun::shellQuote(QString &_str) | 282 | void KRun::shellQuote(QString &_str) | ||
286 | { | 283 | { | ||
287 | // Credits to Walter, says Bernd G. :) | 284 | // Credits to Walter, says Bernd G. :) | ||
288 | if (_str.isEmpty()) { // Don't create an explicit empty parameter | 285 | if (_str.isEmpty()) { // Don't create an explicit empty parameter | ||
289 | return; | 286 | return; | ||
290 | } | 287 | } | ||
291 | const QChar q = QLatin1Char('\''); | 288 | const QChar q = QLatin1Char('\''); | ||
dfaure: rename to `file` now that it's used for both | |||||
292 | _str.replace(q, QLatin1String("'\\''")).prepend(q).append(q); | 289 | _str.replace(q, QLatin1String("'\\''")).prepend(q).append(q); | ||
maybe this function could return the error string on failure as out parameter, so ... pino: maybe this function could return the error string on failure as out parameter, so ... | |||||
293 | } | 290 | } | ||
294 | #endif | 291 | #endif | ||
295 | 292 | | |||
296 | QStringList KRun::processDesktopExec(const KService &_service, const QList<QUrl> &_urls, bool tempFiles, const QString &suggestedFileName) | 293 | QStringList KRun::processDesktopExec(const KService &_service, const QList<QUrl> &_urls, bool tempFiles, const QString &suggestedFileName) | ||
297 | { | 294 | { | ||
298 | KIO::DesktopExecParser parser(_service, _urls); | 295 | KIO::DesktopExecParser parser(_service, _urls); | ||
299 | parser.setUrlsAreTempFiles(tempFiles); | 296 | parser.setUrlsAreTempFiles(tempFiles); | ||
300 | parser.setSuggestedFileName(suggestedFileName); | 297 | parser.setSuggestedFileName(suggestedFileName); | ||
▲ Show 20 Lines • Show All 799 Lines • ▼ Show 20 Line(s) | |||||
1100 | { | 1097 | { | ||
1101 | if (m_strURL == QUrl(QStringLiteral("remote:/x-wizard_service.desktop"))) { | 1098 | if (m_strURL == QUrl(QStringLiteral("remote:/x-wizard_service.desktop"))) { | ||
1102 | return false; | 1099 | return false; | ||
1103 | } | 1100 | } | ||
1104 | const QMimeDatabase db; | 1101 | const QMimeDatabase db; | ||
1105 | const QMimeType mime = db.mimeTypeForUrl(m_strURL); | 1102 | const QMimeType mime = db.mimeTypeForUrl(m_strURL); | ||
1106 | 1103 | | |||
1107 | const bool isFileExecutable = (isExecutableFile(m_strURL, mime.name()) || | 1104 | const bool isFileExecutable = (isExecutableFile(m_strURL, mime.name()) || | ||
1108 | mime.inherits(QStringLiteral("application/x-desktop"))); | 1105 | mime.inherits(QStringLiteral("application/x-desktop"))); | ||
dfaure: This can be removed now that isExecutableFile returns true for desktop files. | |||||
isExecutableFile will return false if the file doesn't have +x bit, which will result in prompt not being show, so I dont think this should be removed. mdlubakowski: isExecutableFile will return false if the file doesn't have +x bit, which will result in prompt… | |||||
Ah. Hmm. I see. This code is confusing. But other than the naming, it makes sense, this code is actually about the edit-or-execute prompt for +x scripts and (any) desktop files. dfaure: Ah. Hmm. I see. This code is confusing.
isFileExecutable will then be true for a non-+x desktop… | |||||
1109 | const bool isTextFile = mime.inherits(QStringLiteral("text/plain")); | 1106 | const bool isTextFile = mime.inherits(QStringLiteral("text/plain")); | ||
1110 | 1107 | | |||
1111 | if (isFileExecutable && isTextFile) { | 1108 | if (isFileExecutable && isTextFile) { | ||
1112 | KConfigGroup cfgGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts"); | 1109 | KConfigGroup cfgGroup(KSharedConfig::openConfig(QStringLiteral("kiorc")), "Executable scripts"); | ||
1113 | const QString value = cfgGroup.readEntry("behaviourOnLaunch", "alwaysAsk"); | 1110 | const QString value = cfgGroup.readEntry("behaviourOnLaunch", "alwaysAsk"); | ||
1114 | 1111 | | |||
1115 | if (value == QLatin1String("alwaysAsk")) { | 1112 | if (value == QLatin1String("alwaysAsk")) { | ||
1116 | return true; | 1113 | return true; | ||
▲ Show 20 Lines • Show All 183 Lines • ▼ Show 20 Line(s) | 1289 | if (errCode) { | |||
1300 | } | 1297 | } | ||
1301 | 1298 | | |||
1302 | d->m_bFinished = true; | 1299 | d->m_bFinished = true; | ||
1303 | // will emit the error and autodelete this | 1300 | // will emit the error and autodelete this | ||
1304 | d->startTimer(); | 1301 | d->startTimer(); | ||
1305 | } | 1302 | } | ||
1306 | } | 1303 | } | ||
1307 | 1304 | | |||
1305 | void KRun::slotChmodFinished(KJob *job) | ||||
1306 | { | ||||
1307 | d->m_job = nullptr; | ||||
1308 | const int errCode = job->error(); | ||||
1309 | if (errCode) { | ||||
1310 | // ERR_NO_CONTENT is not an error, but an indication no further | ||||
1311 | // actions needs to be taken. | ||||
1312 | if (errCode != KIO::ERR_NO_CONTENT) { | ||||
1313 | qCWarning(KIO_WIDGETS) << this << "ERROR (stat):" << job->error() << ' ' << job->errorString(); | ||||
1314 | handleError(job); | ||||
1315 | | ||||
1316 | d->m_bFault = true; | ||||
1317 | } | ||||
1318 | } else { | ||||
1319 | //If job was succesfull, then restart KRun for the same file. | ||||
1320 | KRun *rerun = new KRun(d->m_strURL, d->m_window, d->m_bProgressInfo, d->m_asn); | ||||
1321 | } | ||||
1322 | setFinished(true); | ||||
1323 | } | ||||
1324 | | ||||
1308 | void KRun::mimeTypeDetermined(const QString &mimeType) | 1325 | void KRun::mimeTypeDetermined(const QString &mimeType) | ||
1309 | { | 1326 | { | ||
1310 | // foundMimeType reimplementations might show a dialog box; | 1327 | // foundMimeType reimplementations might show a dialog box; | ||
1311 | // make sure some timer doesn't kill us meanwhile (#137678, #156447) | 1328 | // make sure some timer doesn't kill us meanwhile (#137678, #156447) | ||
1312 | Q_ASSERT(!d->m_showingDialog); | 1329 | Q_ASSERT(!d->m_showingDialog); | ||
1313 | d->m_showingDialog = true; | 1330 | d->m_showingDialog = true; | ||
1314 | 1331 | | |||
1315 | foundMimeType(mimeType); | 1332 | foundMimeType(mimeType); | ||
▲ Show 20 Lines • Show All 48 Lines • ▼ Show 20 Line(s) | 1380 | if (!mime.isValid()) { | |||
1364 | qCWarning(KIO_WIDGETS) << "Unknown mimetype " << type; | 1381 | qCWarning(KIO_WIDGETS) << "Unknown mimetype " << type; | ||
1365 | } else if (mime.inherits(QStringLiteral("application/x-desktop")) && !d->m_localPath.isEmpty()) { | 1382 | } else if (mime.inherits(QStringLiteral("application/x-desktop")) && !d->m_localPath.isEmpty()) { | ||
1366 | d->m_strURL = QUrl::fromLocalFile(d->m_localPath); | 1383 | d->m_strURL = QUrl::fromLocalFile(d->m_localPath); | ||
1367 | } | 1384 | } | ||
1368 | 1385 | | |||
1369 | KRun::RunFlags runFlags; | 1386 | KRun::RunFlags runFlags; | ||
1370 | if (d->m_runExecutables) { | 1387 | if (d->m_runExecutables) { | ||
1371 | runFlags |= KRun::RunExecutables; | 1388 | runFlags |= KRun::RunExecutables; | ||
1389 | //If file is executable but doesn't have +x permission, ask user if he wants to set +x | ||||
dfaure: is *an* executable
(otherwise this sentence is very confusing) | |||||
mdlubakowski: This line is now removed | |||||
1390 | if (!isExecutableFile(d->m_strURL, type) && isExecutable(type)) { | ||||
What happens for desktop files? Won't this go into this code, before going into the existing code to make desktop files executable? dfaure: What happens for desktop files? Won't this go into this code, before going into the existing… | |||||
Moved all the code to KRun::runUrl instead, so it doesnt intercept anything mdlubakowski: Moved all the code to KRun::runUrl instead, so it doesnt intercept anything | |||||
1391 | KMessageBox::ButtonCode makeExecutable = KMessageBox::questionYesNo( | ||||
1392 | d->m_window, | ||||
1393 | i18n("File <b>%1</b> is not marked as executable. Do you wish to run it? <br>" | ||||
1394 | "Keep in mind that if you don't know the source of this file, it may be unsafe to run it!", | ||||
1395 | d->m_strURL.toLocalFile()), | ||||
1396 | i18n("Run executable file"), | ||||
1397 | KGuiItem(i18n("Make executable and run")), | ||||
1398 | KGuiItem(i18n("Open")) | ||||
1399 | ); | ||||
1400 | //If the answer was Yes, start KIO::chmod job | ||||
1401 | if (makeExecutable == KMessageBox::ButtonCode::Yes) { | ||||
1402 | KFileItem binaryFile(d->m_strURL); | ||||
1403 | mode_t newPermissions = binaryFile.permissions() | S_IXUSR; | ||||
1404 | KIO::Job* chmodJob = KIO::chmod(d->m_strURL, newPermissions); | ||||
Only local files can be executed anyway, so you could use file.setPermissions(QFile::ExeUser | file.permissions()) like makeFileExecutable does for desktop files. Actually maybe you could reuse more of that code? dfaure: Only local files can be executed anyway, so you could use file.setPermissions(QFile::ExeUser |… | |||||
1405 | connect(chmodJob, &KJob::result, | ||||
1406 | this, &KRun::slotChmodFinished); | ||||
1407 | chmodJob->start(); | ||||
1408 | d->m_job = chmodJob; | ||||
1409 | //Stop further execution, it will later be restarted or abandoned after the job finishes | ||||
1410 | return; | ||||
1411 | } | ||||
1412 | //If the answer was No, then execute normally | ||||
1372 | } | 1413 | } | ||
1414 | } | ||||
1415 | | ||||
pino: extra empty line | |||||
1373 | if (!KRun::runUrl(d->m_strURL, type, d->m_window, runFlags, d->m_suggestedFileName, d->m_asn)) { | 1416 | if (!KRun::runUrl(d->m_strURL, type, d->m_window, runFlags, d->m_suggestedFileName, d->m_asn)) { | ||
1374 | d->m_bFault = true; | 1417 | d->m_bFault = true; | ||
1375 | } | 1418 | } | ||
1376 | setFinished(true); | 1419 | setFinished(true); | ||
1377 | } | 1420 | } | ||
1378 | 1421 | | |||
1379 | void KRun::killJob() | 1422 | void KRun::killJob() | ||
1380 | { | 1423 | { | ||
▲ Show 20 Lines • Show All 100 Lines • ▼ Show 20 Line(s) | |||||
1481 | 1524 | | |||
1482 | QString KRun::suggestedFileName() const | 1525 | QString KRun::suggestedFileName() const | ||
1483 | { | 1526 | { | ||
1484 | return d->m_suggestedFileName; | 1527 | return d->m_suggestedFileName; | ||
1485 | } | 1528 | } | ||
1486 | 1529 | | |||
1487 | bool KRun::isExecutable(const QString &serviceType) | 1530 | bool KRun::isExecutable(const QString &serviceType) | ||
1488 | { | 1531 | { | ||
1489 | return (serviceType == QLatin1String("application/x-desktop") || | 1532 | QMimeDatabase db; | ||
1490 | serviceType == QLatin1String("application/x-executable") || | 1533 | QMimeType mimeType = db.mimeTypeForName(serviceType); | ||
1534 | return (mimeType.inherits(QLatin1String("application/x-desktop")) || | ||||
1535 | mimeType.inherits(QLatin1String("application/x-executable")) || | ||||
1491 | /* See https://bugs.freedesktop.org/show_bug.cgi?id=97226 */ | 1536 | /* See https://bugs.freedesktop.org/show_bug.cgi?id=97226 */ | ||
1492 | serviceType == QLatin1String("application/x-sharedlib") || | 1537 | mimeType.inherits(QLatin1String("application/x-sharedlib")) || | ||
1493 | serviceType == QLatin1String("application/x-ms-dos-executable") || | 1538 | mimeType.inherits(QLatin1String("application/x-ms-dos-executable")) || | ||
1494 | serviceType == QLatin1String("application/x-shellscript")); | 1539 | mimeType.inherits(QLatin1String("application/x-shellscript"))); | ||
1495 | } | 1540 | } | ||
1496 | 1541 | | |||
1497 | void KRun::setUrl(const QUrl &url) | 1542 | void KRun::setUrl(const QUrl &url) | ||
1498 | { | 1543 | { | ||
1499 | d->m_strURL = url; | 1544 | d->m_strURL = url; | ||
1500 | } | 1545 | } | ||
1501 | 1546 | | |||
1502 | QUrl KRun::url() const | 1547 | QUrl KRun::url() const | ||
▲ Show 20 Lines • Show All 176 Lines • Show Last 20 Lines |
I wonder why this doesn't use isExecutable(mimetype)...