34 #include <QtGui/QWidget>
35 #include <QtGui/QLabel>
36 #include <QtGui/QVBoxLayout>
37 #include <QtGui/QHBoxLayout>
38 #include <QtGui/QPlainTextEdit>
39 #include <QtGui/QApplication>
40 #include <QtGui/QDesktopWidget>
64 #include <QtCore/QFile>
65 #include <QtCore/QFileInfo>
66 #include <QtCore/QTextIStream>
67 #include <QtCore/QDate>
68 #include <QtCore/QRegExp>
73 #include <QTextDocument>
87 m_showingDialog(false)
104 if (file.isExecutable()) {
106 if (mimeType && (mimeType->
is(QLatin1String(
"application/x-executable")) ||
108 mimeType->
is(QLatin1String(
"application/x-ms-dos-executable")) ||
110 mimeType->
is(QLatin1String(
"application/x-executable-script")))
124 if (_mimetype == QLatin1String(
"inode/directory-locked")) {
126 i18n(
"<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", Qt::escape(u.
prettyUrl())));
129 else if (_mimetype == QLatin1String(
"application/x-desktop")) {
144 else if (_mimetype == QLatin1String(
"application/x-executable")) {
149 if (!runExecutables) {
160 i18n(
"<qt>The file <b>%1</b> is an executable program. "
161 "For safety it will not be started.</qt>", Qt::escape(u.
prettyUrl())));
166 i18n(
"<qt>You do not have permission to run <b>%1</b>.</qt>", Qt::escape(u.
prettyUrl())));
182 return KRun::run(*offer, lst, window, tempFile, suggestedFileName, asn);
190 i18n(
"You are not authorized to select an application to open this file."));
196 if (cfgGroup.
readEntry(
"Native",
true)) {
198 suggestedFileName, asn);
205 kDebug(7010) <<
"No service set, running " << l.
text();
208 return KRun::run(*service, lst, window, tempFiles, suggestedFileName, asn);
213 #ifndef KDE_NO_DEPRECATED
217 if (_str.isEmpty()) {
221 _str.replace(q,
"'\\''").prepend(q).append(q);
232 bool hasUrls: 1, hasSpec: 1;
244 uint option = str[pos + 1].unicode();
247 ret << service.name().replace(
'%',
"%%");
250 ret << service.entryPath().replace(
'%',
"%%");
253 ret <<
"--icon" << service.icon().replace(
'%',
"%%");
257 kWarning() <<
"-miniicon isn't supported anymore (service"
258 << service.name() <<
')';
301 ret << ((url.
isLocalFile() && url.fragment().isNull() && url.encodedQuery().isNull()) ?
308 ret << QDir::toNativeSeparators(url.
toLocalFile());
325 uint option = str[pos + 1].unicode();
332 if (urls.isEmpty()) {
334 kDebug() <<
"No URLs supplied to single-URL service" << str;
337 else if (urls.count() > 1) {
338 kWarning() << urls.count() <<
"URLs supplied to single-URL service" << str;
341 subst(option, urls.first(), ret);
349 for (KUrl::List::ConstIterator it = urls.begin(); it != urls.end(); ++it)
350 subst(option, *it, ret);
366 KRunMX1 mx1(_service);
368 if (mx1.expandMacrosShellQuote(exec) && !mx1.hasUrls) {
369 Q_ASSERT(supportedProtocols.isEmpty());
372 if (supportedProtocols.isEmpty()) {
375 if (categories.contains(
"KDE")
378 supportedProtocols.append(
"KIO");
381 supportedProtocols.append(
"http");
382 supportedProtocols.append(
"https");
383 supportedProtocols.append(
"ftp");
393 if (supportedProtocols.contains(
"KIO"))
401 if (exec.isEmpty()) {
407 bool appHasTempFileOption;
409 KRunMX1 mx1(_service);
412 if (!mx1.expandMacrosShellQuote(exec)) {
413 kWarning() <<
"KRun: syntax error in command" << _service.
exec() <<
", service" << _service.
name();
420 appHasTempFileOption = tempFiles && _service.
property(
"X-KDE-HasTempFileOption").toBool();
421 if (tempFiles && !appHasTempFileOption && _urls.size()) {
423 Q_ASSERT(!kioexec.isEmpty());
424 result << kioexec <<
"--tempfiles" << exec;
425 if (!suggestedFileName.isEmpty()) {
426 result <<
"--suggestedfilename";
434 bool useKioexec =
false;
436 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
439 kDebug(7010) <<
"non-local files, application does not support urls, using kioexec";
444 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
447 kDebug(7010) <<
"application does not support url, using kioexec:" << *it;
454 Q_ASSERT(!kioexec.isEmpty());
457 result <<
"--tempfiles";
459 if (!suggestedFileName.isEmpty()) {
460 result <<
"--suggestedfilename";
468 if (appHasTempFileOption) {
469 exec +=
" --tempfile";
480 mx2.expandMacrosShellQuote(exec);
502 if (terminal ==
"konsole") {
503 if (!_service.
path().isEmpty()) {
506 terminal +=
" -caption=%c %i %m";
510 if (!mx1.expandMacrosShellQuote(terminal)) {
511 kWarning() <<
"KRun: syntax error in command" << terminal <<
", service" << _service.
name();
514 mx2.expandMacrosShellQuote(terminal);
525 if (!exePath.isEmpty()) {
526 execlist[0] = exePath;
537 result << _service.
username() <<
"-c";
548 result <<
"/bin/sh" <<
"-c" << exec;
563 for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
564 if (!(*it).contains(
'=')) {
566 return removePath ? (*it).mid((*it).lastIndexOf(
'/') + 1) : *it;
573 const QByteArray& asn)
575 if (window != NULL) {
576 window = window->topLevelWidget();
578 if (service && !service->
entryPath().isEmpty()
588 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
593 if (startup_notify) {
595 id.setupStartupEnv();
599 if (!userVisibleName.isEmpty()) {
602 else if (service && !service->
name().isEmpty()) {
606 if (!iconName.isEmpty()) {
609 else if (service && !service->
icon().isEmpty()) {
612 if (!wmclass.isEmpty()) {
622 if(service && !service->
entryPath().isEmpty())
627 if (startup_notify && pid) {
635 Q_UNUSED(userVisibleName);
646 if (service && service->
property(
"StartupNotify").isValid()) {
647 silent = !service->
property(
"StartupNotify").toBool();
648 wmclass = service->
property(
"StartupWMClass").toString().toLatin1();
650 else if (service && service->
property(
"X-KDE-StartupNotify").isValid()) {
651 silent = !service->
property(
"X-KDE-StartupNotify").toBool();
652 wmclass = service->
property(
"X-KDE-WMClass").toString().toLatin1();
670 #else // That unfortunately doesn't work, when the launched non-compliant application
676 if (silent_arg != NULL) {
677 *silent_arg = silent;
679 if (wmclass_arg != NULL) {
680 *wmclass_arg = wmclass;
688 if (!_urls.isEmpty()) {
689 kDebug(7010) <<
"runTempService: first url " << _urls.first().url();
699 KUrl::List::ConstIterator it = _urls.begin();
700 while (++it != _urls.end()) {
702 singleUrl.append(*it);
703 runTempService(_service, singleUrl, window, tempFiles, suggestedFileName, QByteArray());
706 singleUrl.append(_urls.first());
712 if (args.isEmpty()) {
716 kDebug(7010) <<
"runTempService: KProcess args=" << args;
721 if (!_service.
path().isEmpty()) {
722 proc->setWorkingDirectory(_service.
path());
736 if (!appSupportedProtocols.contains(
"KIO")) {
737 for (KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it) {
738 const KUrl url = *it;
740 kDebug(7010) <<
"Looking at url=" << url <<
" supported=" << supported;
744 if (localURL != url) {
746 kDebug(7010) <<
"Changed to " << localURL;
756 class SecureMessageDialog :
public KDialog
759 SecureMessageDialog(
QWidget *parent) :
KDialog(parent), m_textEdit(0)
763 void setTextEdit(QPlainTextEdit *textEdit)
765 m_textEdit = textEdit;
769 virtual void showEvent(QShowEvent* e)
773 KDialog::showEvent(e);
782 QRect curRect(m_textEdit->rect());
783 QFontMetrics metrics(fontMetrics());
784 curRect.setHeight(5 * metrics.lineSpacing());
785 curRect.setWidth(qMax(curRect.width(), 300));
787 QString text(m_textEdit->toPlainText());
788 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
792 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
793 if(curRect.height() < m_textEdit->height()) {
794 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
795 m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
798 m_textEdit->setMinimumSize(curRect.size() + fudge);
799 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
804 QPlainTextEdit *m_textEdit;
815 QFile desktopFile(fileName);
816 if (!desktopFile.open(QFile::ReadOnly)) {
817 kError(7010) <<
"Error opening service" << fileName << desktopFile.errorString();
821 QByteArray
header = desktopFile.peek(2);
822 if (header.size() == 0) {
823 kError(7010) <<
"Error inspecting service" << fileName << desktopFile.errorString();
827 if (header !=
"#!") {
831 if (!saveFile.
open()) {
832 kError(7010) <<
"Unable to open replacement file for" << fileName << saveFile.
errorString();
836 QByteArray shebang(
"#!/usr/bin/env xdg-open\n");
837 if (saveFile.write(shebang) != shebang.size()) {
838 kError(7010) <<
"Error occurred adding header for" << fileName << saveFile.
errorString();
844 QByteArray desktopData(desktopFile.readAll());
845 if (desktopData.isEmpty()) {
846 kError(7010) <<
"Unable to read service" << fileName << desktopFile.errorString();
851 if (saveFile.write(desktopData) != desktopData.size()) {
859 kError(7010) <<
"Error committing changes to service" << fileName << saveFile.
errorString();
863 if (!desktopFile.open(QFile::ReadOnly)) {
864 kError(7010) <<
"Error re-opening service" << fileName << desktopFile.errorString();
871 if (!desktopFile.setPermissions(QFile::ExeUser | desktopFile.permissions())) {
872 kError(7010) <<
"Unable to change permissions for" << fileName << desktopFile.errorString();
893 SecureMessageDialog *baseDialog =
new SecureMessageDialog(window);
896 baseDialog->setButtonGuiItem(
KDialog::Ok, continueItem);
899 baseDialog->setCaption(
i18nc(
"Warning about executing unknown .desktop file",
"Warning"));
904 QHBoxLayout *mainLayout =
new QHBoxLayout(baseWidget);
908 mainLayout->addWidget(iconLabel);
909 iconLabel->setPixmap(warningIcon);
911 QVBoxLayout *contentLayout =
new QVBoxLayout;
912 QString warningMessage =
i18nc(
"program name follows in a line edit below",
913 "This will start the program:");
916 contentLayout->addWidget(message);
922 QPlainTextEdit *textEdit =
new QPlainTextEdit(baseWidget);
923 textEdit->setPlainText(program);
924 textEdit->setReadOnly(
true);
925 contentLayout->addWidget(textEdit);
927 QLabel *footerLabel =
new QLabel(
i18n(
"If you do not trust this program, click Cancel"));
928 contentLayout->addWidget(footerLabel);
929 contentLayout->addStretch(0);
931 mainLayout->addLayout(contentLayout);
933 baseDialog->setMainWidget(baseWidget);
934 baseDialog->setTextEdit(textEdit);
938 QSize screenSize = QApplication::desktop()->screen()->size();
939 baseDialog->resize(screenSize.width() / 4, 50);
940 baseDialog->setMaximumHeight(screenSize.height() / 3);
941 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
943 int result = baseDialog->exec();
944 if (result != KDialog::Accepted) {
955 if(serviceName.isEmpty())
960 i18n(
"Unable to make the service %1 executable, aborting execution", serviceName)
981 KUrl::List::ConstIterator it = _urls.begin();
982 for (; it != _urls.end(); ++it) {
988 if (tempFiles || _service.
entryPath().isEmpty() || !suggestedFileName.isEmpty()) {
989 return runTempService(_service, _urls, window, tempFiles, suggestedFileName, asn);
994 if (!_urls.isEmpty()) {
995 kDebug(7010) <<
"First url " << _urls.first().url();
1004 QByteArray myasn = asn;
1006 if (window != NULL) {
1007 if (myasn.isEmpty()) {
1029 kDebug(7010) <<
"startServiceByDesktopPath worked fine";
1035 const QString& _icon,
const QByteArray& asn)
1039 return run(*service, _urls, window,
false,
QString(), asn);
1049 if (cmd.isEmpty()) {
1050 kWarning() <<
"Command was empty, nothing to run";
1055 if (args.isEmpty()) {
1056 kWarning() <<
"Command could not be parsed.";
1060 const QString bin = args.first();
1061 return KRun::runCommand(cmd, bin, bin , window, QByteArray(), workingDirectory);
1072 kDebug(7010) <<
"runCommand " << cmd <<
"," << execName;
1075 if (!workingDirectory.isEmpty()) {
1076 proc->setWorkingDirectory(workingDirectory);
1087 bool showProgressInfo,
const QByteArray& asn)
1090 d->
m_timer.setObjectName(
"KRun::timer");
1091 d->
m_timer.setSingleShot(
true);
1092 d->
init(url, window, mode, isLocalFile, showProgressInfo, asn);
1096 bool showProgressInfo,
const QByteArray& asn)
1126 kDebug(7010) <<
"INIT called";
1158 KDE_struct_stat buff;
1162 i18n(
"<qt>Unable to run the command specified. "
1163 "The file or folder <b>%1</b> does not exist.</qt>" ,
1171 d->
m_mode = buff.st_mode;
1176 kDebug(7010) <<
"MIME TYPE is " << mime->
name();
1178 (mime->
is(QLatin1String(
"text/html")) ||
1179 mime->
is(QLatin1String(
"application/xhtml+xml")))) {
1199 kDebug(7010) <<
"Helper protocol";
1201 if (exec.isEmpty()) {
1214 if (S_ISDIR(d->
m_mode)) {
1228 kDebug(7010) <<
"Testing directory (stating)";
1234 connect(job, SIGNAL(result(
KJob*)),
1253 urls.append(m_strURL);
1254 if (_exec.startsWith(
'!')) {
1265 if (service && q->run(*service, urls, m_window,
false,
QString(), m_asn)) {
1283 kDebug(7010) <<
"Scanfile: MIME TYPE is " << mime->
name();
1294 kError(7010) <<
"#### NO SUPPORT FOR READING!";
1305 connect(job, SIGNAL(result(
KJob*)),
1310 kDebug(7010) <<
" Job " << job <<
" is about getting from " << d->
m_strURL.
url();
1317 kDebug(7010) <<
this <<
" slotTimeout called";
1352 const int errCode = job->
error();
1371 kDebug(7010) <<
"Finished";
1375 kFatal() <<
"job is a " <<
typeid(*job).name() <<
" should be a StatJob";
1383 if (S_ISDIR(mode)) {
1395 if (!knownMimeType.isEmpty()) {
1412 if (mimetype.isEmpty()) {
1413 kWarning(7010) <<
"get() didn't emit a mimetype! Probably a kioslave bug, please check the implementation of" <<
url().
protocol();
1422 const int errCode = job->
error();
1459 kDebug(7010) <<
"Resulting mime type is " << type;
1494 kWarning(7010) <<
"Unknown mimetype " << type;
1496 if (mime && mime->
is(
"application/x-desktop") && !d->
m_localPath.isEmpty()) {
1594 return (serviceType ==
"application/x-desktop" ||
1595 serviceType ==
"application/x-executable" ||
1596 serviceType ==
"application/x-ms-dos-executable" ||
1597 serviceType ==
"application/x-shellscript");
1642 #ifndef KDE_NO_DEPRECATED
1649 #ifndef KDE_NO_DEPRECATED
1656 #ifndef KDE_NO_DEPRECATED
1663 #ifndef KDE_NO_DEPRECATED
1675 #ifndef KDE_NO_DEPRECATED
1682 #ifndef KDE_NO_DEPRECATED
1724 KProcessRunner::KProcessRunner(
KProcess * p,
const QString & executable)
1732 m_executable = executable;
1733 connect(process, SIGNAL(finished(
int,QProcess::ExitStatus)),
1737 if (!process->waitForStarted()) {
1745 m_pid = process->
pid();
1760 void KProcessRunner::terminateStartupNotification()
1776 kDebug(7010) << m_executable <<
"exitCode=" << exitCode <<
"exitStatus=" << exitStatus;
1777 Q_UNUSED(exitStatus);
1779 terminateStartupNotification();
1780 if (exitCode != 0 && !m_executable.isEmpty()) {
1793 kDebug() << process->readAllStandardError();
1800 #include "krun_p.moc"