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>
65 #include <QtCore/QFile>
66 #include <QtCore/QFileInfo>
67 #include <QtCore/QTextIStream>
68 #include <QtCore/QDate>
69 #include <QtCore/QRegExp>
74 #include <QTextDocument>
88 m_showingDialog(false)
105 if (file.isExecutable()) {
107 if (mimeType && (mimeType->
is(QLatin1String(
"application/x-executable")) ||
109 mimeType->
is(QLatin1String(
"application/x-ms-dos-executable")) ||
111 mimeType->
is(QLatin1String(
"application/x-executable-script")))
125 if (_mimetype == QLatin1String(
"inode/directory-locked")) {
127 i18n(
"<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", Qt::escape(u.
prettyUrl())));
130 else if (_mimetype == QLatin1String(
"application/x-desktop")) {
145 else if (_mimetype == QLatin1String(
"application/x-executable")) {
150 if (!runExecutables) {
161 i18n(
"<qt>The file <b>%1</b> is an executable program. "
162 "For safety it will not be started.</qt>", Qt::escape(u.
prettyUrl())));
167 i18n(
"<qt>You do not have permission to run <b>%1</b>.</qt>", Qt::escape(u.
prettyUrl())));
183 return KRun::run(*offer, lst, window, tempFile, suggestedFileName, asn);
191 i18n(
"You are not authorized to select an application to open this file."));
197 if (cfgGroup.
readEntry(
"Native",
true)) {
199 suggestedFileName, asn);
206 kDebug(7010) <<
"No service set, running " << l.
text();
209 return KRun::run(*service, lst, window, tempFiles, suggestedFileName, asn);
214 #ifndef KDE_NO_DEPRECATED
218 if (_str.isEmpty()) {
222 _str.replace(q,
"'\\''").prepend(q).append(q);
233 bool hasUrls: 1, hasSpec: 1;
245 uint option = str[pos + 1].unicode();
248 ret << service.name().replace(
'%',
"%%");
251 ret << service.entryPath().replace(
'%',
"%%");
254 ret <<
"--icon" << service.icon().replace(
'%',
"%%");
258 kWarning() <<
"-miniicon isn't supported anymore (service"
259 << service.name() <<
')';
302 ret << ((url.
isLocalFile() && url.fragment().isNull() && url.encodedQuery().isNull()) ?
309 ret << QDir::toNativeSeparators(url.
toLocalFile());
326 uint option = str[pos + 1].unicode();
333 if (urls.isEmpty()) {
335 kDebug() <<
"No URLs supplied to single-URL service" << str;
338 else if (urls.count() > 1) {
339 kWarning() << urls.count() <<
"URLs supplied to single-URL service" << str;
342 subst(option, urls.first(), ret);
350 for (KUrl::List::ConstIterator it = urls.begin(); it != urls.end(); ++it)
351 subst(option, *it, ret);
367 KRunMX1 mx1(_service);
369 if (mx1.expandMacrosShellQuote(exec) && !mx1.hasUrls) {
370 Q_ASSERT(supportedProtocols.isEmpty());
373 if (supportedProtocols.isEmpty()) {
376 if (categories.contains(
"KDE")
379 supportedProtocols.append(
"KIO");
382 supportedProtocols.append(
"http");
383 supportedProtocols.append(
"https");
384 supportedProtocols.append(
"ftp");
394 if (supportedProtocols.contains(
"KIO"))
402 if (exec.isEmpty()) {
408 bool appHasTempFileOption;
410 KRunMX1 mx1(_service);
413 if (!mx1.expandMacrosShellQuote(exec)) {
414 kWarning() <<
"KRun: syntax error in command" << _service.
exec() <<
", service" << _service.
name();
421 appHasTempFileOption = tempFiles && _service.
property(
"X-KDE-HasTempFileOption").toBool();
422 if (tempFiles && !appHasTempFileOption && _urls.size()) {
424 Q_ASSERT(!kioexec.isEmpty());
425 result << kioexec <<
"--tempfiles" << exec;
426 if (!suggestedFileName.isEmpty()) {
427 result <<
"--suggestedfilename";
435 bool useKioexec =
false;
437 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
440 kDebug(7010) <<
"non-local files, application does not support urls, using kioexec";
445 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
448 kDebug(7010) <<
"application does not support url, using kioexec:" << *it;
455 Q_ASSERT(!kioexec.isEmpty());
458 result <<
"--tempfiles";
460 if (!suggestedFileName.isEmpty()) {
461 result <<
"--suggestedfilename";
469 if (appHasTempFileOption) {
470 exec +=
" --tempfile";
481 mx2.expandMacrosShellQuote(exec);
503 if (terminal ==
"konsole") {
504 if (!_service.
path().isEmpty()) {
507 terminal +=
" -caption=%c %i %m";
511 if (!mx1.expandMacrosShellQuote(terminal)) {
512 kWarning() <<
"KRun: syntax error in command" << terminal <<
", service" << _service.
name();
515 mx2.expandMacrosShellQuote(terminal);
526 if (!exePath.isEmpty()) {
527 execlist[0] = exePath;
538 result << _service.
username() <<
"-c";
549 result <<
"/bin/sh" <<
"-c" << exec;
564 for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
565 if (!(*it).contains(
'=')) {
567 return removePath ? (*it).mid((*it).lastIndexOf(
'/') + 1) : *it;
574 const QByteArray& asn)
576 if (window != NULL) {
577 window = window->topLevelWidget();
579 if (service && !service->
entryPath().isEmpty()
589 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
594 if (startup_notify) {
596 id.setupStartupEnv();
600 if (!userVisibleName.isEmpty()) {
603 else if (service && !service->
name().isEmpty()) {
607 if (!iconName.isEmpty()) {
610 else if (service && !service->
icon().isEmpty()) {
613 if (!wmclass.isEmpty()) {
623 if(service && !service->
entryPath().isEmpty())
628 if (startup_notify && pid) {
636 Q_UNUSED(userVisibleName);
647 if (service && service->
property(
"StartupNotify").isValid()) {
648 silent = !service->
property(
"StartupNotify").toBool();
649 wmclass = service->
property(
"StartupWMClass").toString().toLatin1();
651 else if (service && service->
property(
"X-KDE-StartupNotify").isValid()) {
652 silent = !service->
property(
"X-KDE-StartupNotify").toBool();
653 wmclass = service->
property(
"X-KDE-WMClass").toString().toLatin1();
671 #else // That unfortunately doesn't work, when the launched non-compliant application
677 if (silent_arg != NULL) {
678 *silent_arg = silent;
680 if (wmclass_arg != NULL) {
681 *wmclass_arg = wmclass;
689 if (!_urls.isEmpty()) {
690 kDebug(7010) <<
"runTempService: first url " << _urls.first().url();
700 KUrl::List::ConstIterator it = _urls.begin();
701 while (++it != _urls.end()) {
703 singleUrl.append(*it);
704 runTempService(_service, singleUrl, window, tempFiles, suggestedFileName, QByteArray());
707 singleUrl.append(_urls.first());
713 if (args.isEmpty()) {
717 kDebug(7010) <<
"runTempService: KProcess args=" << args;
722 if (!_service.
path().isEmpty()) {
723 proc->setWorkingDirectory(_service.
path());
727 _service.
name(), _service.
icon(), window, asn);
737 if (!appSupportedProtocols.contains(
"KIO")) {
738 for (KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it) {
739 const KUrl url = *it;
741 kDebug(7010) <<
"Looking at url=" << url <<
" supported=" << supported;
745 if (localURL != url) {
747 kDebug(7010) <<
"Changed to " << localURL;
757 class SecureMessageDialog :
public KDialog
760 SecureMessageDialog(
QWidget *parent) :
KDialog(parent), m_textEdit(0)
764 void setTextEdit(QPlainTextEdit *textEdit)
766 m_textEdit = textEdit;
770 virtual void showEvent(QShowEvent* e)
774 KDialog::showEvent(e);
783 QRect curRect(m_textEdit->rect());
784 QFontMetrics metrics(fontMetrics());
785 curRect.setHeight(5 * metrics.lineSpacing());
786 curRect.setWidth(qMax(curRect.width(), 300));
788 QString text(m_textEdit->toPlainText());
789 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
793 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
794 if(curRect.height() < m_textEdit->height()) {
795 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
796 m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
799 m_textEdit->setMinimumSize(curRect.size() + fudge);
800 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
805 QPlainTextEdit *m_textEdit;
816 QFile desktopFile(fileName);
817 if (!desktopFile.open(QFile::ReadOnly)) {
818 kError(7010) <<
"Error opening service" << fileName << desktopFile.errorString();
822 QByteArray
header = desktopFile.peek(2);
823 if (header.size() == 0) {
824 kError(7010) <<
"Error inspecting service" << fileName << desktopFile.errorString();
828 if (header !=
"#!") {
832 if (!saveFile.
open()) {
833 kError(7010) <<
"Unable to open replacement file for" << fileName << saveFile.
errorString();
837 QByteArray shebang(
"#!/usr/bin/env xdg-open\n");
838 if (saveFile.write(shebang) != shebang.size()) {
839 kError(7010) <<
"Error occurred adding header for" << fileName << saveFile.
errorString();
845 QByteArray desktopData(desktopFile.readAll());
846 if (desktopData.isEmpty()) {
847 kError(7010) <<
"Unable to read service" << fileName << desktopFile.errorString();
852 if (saveFile.write(desktopData) != desktopData.size()) {
860 kError(7010) <<
"Error committing changes to service" << fileName << saveFile.
errorString();
864 if (!desktopFile.open(QFile::ReadOnly)) {
865 kError(7010) <<
"Error re-opening service" << fileName << desktopFile.errorString();
872 if (!desktopFile.setPermissions(QFile::ExeUser | desktopFile.permissions())) {
873 kError(7010) <<
"Unable to change permissions for" << fileName << desktopFile.errorString();
894 SecureMessageDialog *baseDialog =
new SecureMessageDialog(window);
897 baseDialog->setButtonGuiItem(
KDialog::Ok, continueItem);
900 baseDialog->setCaption(
i18nc(
"Warning about executing unknown .desktop file",
"Warning"));
905 QHBoxLayout *mainLayout =
new QHBoxLayout(baseWidget);
909 mainLayout->addWidget(iconLabel);
910 iconLabel->setPixmap(warningIcon);
912 QVBoxLayout *contentLayout =
new QVBoxLayout;
913 QString warningMessage =
i18nc(
"program name follows in a line edit below",
914 "This will start the program:");
917 contentLayout->addWidget(message);
923 QPlainTextEdit *textEdit =
new QPlainTextEdit(baseWidget);
924 textEdit->setPlainText(program);
925 textEdit->setReadOnly(
true);
926 contentLayout->addWidget(textEdit);
928 QLabel *footerLabel =
new QLabel(
i18n(
"If you do not trust this program, click Cancel"));
929 contentLayout->addWidget(footerLabel);
930 contentLayout->addStretch(0);
932 mainLayout->addLayout(contentLayout);
934 baseDialog->setMainWidget(baseWidget);
935 baseDialog->setTextEdit(textEdit);
939 QSize screenSize = QApplication::desktop()->screen()->size();
940 baseDialog->resize(screenSize.width() / 4, 50);
941 baseDialog->setMaximumHeight(screenSize.height() / 3);
942 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
944 int result = baseDialog->exec();
945 if (result != KDialog::Accepted) {
956 if(serviceName.isEmpty())
961 i18n(
"Unable to make the service %1 executable, aborting execution", serviceName)
982 KUrl::List::ConstIterator it = _urls.begin();
983 for (; it != _urls.end(); ++it) {
989 if (tempFiles || _service.
entryPath().isEmpty() || !suggestedFileName.isEmpty()) {
990 return runTempService(_service, _urls, window, tempFiles, suggestedFileName, asn);
995 if (!_urls.isEmpty()) {
996 kDebug(7010) <<
"First url " << _urls.first().url();
1005 QByteArray myasn = asn;
1007 if (window != NULL) {
1008 if (myasn.isEmpty()) {
1030 kDebug(7010) <<
"startServiceByDesktopPath worked fine";
1036 const QString& _icon,
const QByteArray& asn)
1040 return run(*service, _urls, window,
false,
QString(), asn);
1050 if (cmd.isEmpty()) {
1051 kWarning() <<
"Command was empty, nothing to run";
1056 if (args.isEmpty()) {
1057 kWarning() <<
"Command could not be parsed.";
1061 const QString bin = args.first();
1062 return KRun::runCommand(cmd, bin, bin , window, QByteArray(), workingDirectory);
1071 QWidget* window,
const QByteArray& asn,
const QString& workingDirectory)
1073 kDebug(7010) <<
"runCommand " << cmd <<
"," << execName;
1076 if (workingDirectory.isEmpty()) {
1081 proc->setWorkingDirectory(workingDirectory);
1088 iconName, window, asn);
1092 bool showProgressInfo,
const QByteArray& asn)
1095 d->
m_timer.setObjectName(
"KRun::timer");
1096 d->
m_timer.setSingleShot(
true);
1097 d->
init(url, window, mode, isLocalFile, showProgressInfo, asn);
1101 bool showProgressInfo,
const QByteArray& asn)
1131 kDebug(7010) <<
"INIT called";
1163 KDE_struct_stat buff;
1167 i18n(
"<qt>Unable to run the command specified. "
1168 "The file or folder <b>%1</b> does not exist.</qt>" ,
1176 d->
m_mode = buff.st_mode;
1181 kDebug(7010) <<
"MIME TYPE is " << mime->
name();
1183 mime->
is(QLatin1String(
"text/html")) ||
1184 mime->
is(QLatin1String(
"application/xml")))) {
1194 kDebug(7010) <<
"Helper protocol";
1196 if (exec.isEmpty()) {
1209 if (S_ISDIR(d->
m_mode)) {
1223 kDebug(7010) <<
"Testing directory (stating)";
1229 connect(job, SIGNAL(result(
KJob*)),
1248 urls.append(m_strURL);
1249 if (_exec.startsWith(
'!')) {
1260 if (service && q->run(*service, urls, m_window,
false,
QString(), m_asn)) {
1278 kDebug(7010) <<
"Scanfile: MIME TYPE is " << mime->
name();
1289 kError(7010) <<
"#### NO SUPPORT FOR READING!";
1300 connect(job, SIGNAL(result(
KJob*)),
1305 kDebug(7010) <<
" Job " << job <<
" is about getting from " << d->
m_strURL.
url();
1312 kDebug(7010) <<
this <<
" slotTimeout called";
1347 const int errCode = job->
error();
1366 kDebug(7010) <<
"Finished";
1370 kFatal() <<
"job is a " <<
typeid(*job).name() <<
" should be a StatJob";
1378 if (S_ISDIR(mode)) {
1390 if (!knownMimeType.isEmpty()) {
1407 if (mimetype.isEmpty()) {
1408 kWarning(7010) <<
"get() didn't emit a mimetype! Probably a kioslave bug, please check the implementation of" <<
url().
protocol();
1417 const int errCode = job->
error();
1454 kDebug(7010) <<
"Resulting mime type is " << type;
1489 kWarning(7010) <<
"Unknown mimetype " << type;
1491 if (mime && mime->
is(
"application/x-desktop") && !d->
m_localPath.isEmpty()) {
1584 return (serviceType ==
"application/x-desktop" ||
1585 serviceType ==
"application/x-executable" ||
1586 serviceType ==
"application/x-ms-dos-executable" ||
1587 serviceType ==
"application/x-shellscript");
1632 #ifndef KDE_NO_DEPRECATED
1639 #ifndef KDE_NO_DEPRECATED
1646 #ifndef KDE_NO_DEPRECATED
1653 #ifndef KDE_NO_DEPRECATED
1665 #ifndef KDE_NO_DEPRECATED
1672 #ifndef KDE_NO_DEPRECATED
1714 KProcessRunner::KProcessRunner(
KProcess * p,
const QString & executable)
1722 m_executable = executable;
1723 connect(process, SIGNAL(finished(
int,QProcess::ExitStatus)),
1727 if (!process->waitForStarted()) {
1735 m_pid = process->
pid();
1750 void KProcessRunner::terminateStartupNotification()
1766 kDebug(7010) << m_executable <<
"exitCode=" << exitCode <<
"exitStatus=" << exitStatus;
1767 Q_UNUSED(exitStatus);
1769 terminateStartupNotification();
1770 if (exitCode != 0 && !m_executable.isEmpty()) {
1783 kDebug() << process->readAllStandardError();
1790 #include "krun_p.moc"