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") || !_service.
isApplication()) {
377 supportedProtocols.append(
"KIO");
380 supportedProtocols.append(
"http");
381 supportedProtocols.append(
"https");
382 supportedProtocols.append(
"ftp");
392 if (supportedProtocols.contains(
"KIO"))
400 if (exec.isEmpty()) {
406 bool appHasTempFileOption;
408 KRunMX1 mx1(_service);
411 if (!mx1.expandMacrosShellQuote(exec)) {
412 kWarning() <<
"KRun: syntax error in command" << _service.
exec() <<
", service" << _service.
name();
419 appHasTempFileOption = tempFiles && _service.
property(
"X-KDE-HasTempFileOption").toBool();
420 if (tempFiles && !appHasTempFileOption && _urls.size()) {
422 Q_ASSERT(!kioexec.isEmpty());
423 result << kioexec <<
"--tempfiles" << exec;
424 if (!suggestedFileName.isEmpty()) {
425 result <<
"--suggestedfilename";
433 bool useKioexec =
false;
435 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
438 kDebug(7010) <<
"non-local files, application does not support urls, using kioexec";
443 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
446 kDebug(7010) <<
"application does not support url, using kioexec:" << *it;
453 Q_ASSERT(!kioexec.isEmpty());
456 result <<
"--tempfiles";
458 if (!suggestedFileName.isEmpty()) {
459 result <<
"--suggestedfilename";
467 if (appHasTempFileOption) {
468 exec +=
" --tempfile";
479 mx2.expandMacrosShellQuote(exec);
501 if (terminal ==
"konsole") {
502 if (!_service.
path().isEmpty()) {
505 terminal +=
" -caption=%c %i %m";
509 if (!mx1.expandMacrosShellQuote(terminal)) {
510 kWarning() <<
"KRun: syntax error in command" << terminal <<
", service" << _service.
name();
513 mx2.expandMacrosShellQuote(terminal);
524 if (!exePath.isEmpty()) {
525 execlist[0] = exePath;
536 result << _service.
username() <<
"-c";
547 result <<
"/bin/sh" <<
"-c" << exec;
562 for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
563 if (!(*it).contains(
'=')) {
565 return removePath ? (*it).mid((*it).lastIndexOf(
'/') + 1) : *it;
572 const QByteArray& asn)
574 if (window != NULL) {
575 window = window->topLevelWidget();
577 if (service && !service->
entryPath().isEmpty()
587 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
592 if (startup_notify) {
594 id.setupStartupEnv();
598 if (!userVisibleName.isEmpty()) {
601 else if (service && !service->
name().isEmpty()) {
605 if (!iconName.isEmpty()) {
608 else if (service && !service->
icon().isEmpty()) {
611 if (!wmclass.isEmpty()) {
621 if(service && !service->
entryPath().isEmpty())
626 if (startup_notify && pid) {
634 Q_UNUSED(userVisibleName);
645 if (service && service->
property(
"StartupNotify").isValid()) {
646 silent = !service->
property(
"StartupNotify").toBool();
647 wmclass = service->
property(
"StartupWMClass").toString().toLatin1();
649 else if (service && service->
property(
"X-KDE-StartupNotify").isValid()) {
650 silent = !service->
property(
"X-KDE-StartupNotify").toBool();
651 wmclass = service->
property(
"X-KDE-WMClass").toString().toLatin1();
669 #else // That unfortunately doesn't work, when the launched non-compliant application
675 if (silent_arg != NULL) {
676 *silent_arg = silent;
678 if (wmclass_arg != NULL) {
679 *wmclass_arg = wmclass;
687 if (!_urls.isEmpty()) {
688 kDebug(7010) <<
"runTempService: first url " << _urls.first().url();
698 KUrl::List::ConstIterator it = _urls.begin();
699 while (++it != _urls.end()) {
701 singleUrl.append(*it);
702 runTempService(_service, singleUrl, window, tempFiles, suggestedFileName, QByteArray());
705 singleUrl.append(_urls.first());
711 if (args.isEmpty()) {
715 kDebug(7010) <<
"runTempService: KProcess args=" << args;
720 if (!_service.
path().isEmpty()) {
721 proc->setWorkingDirectory(_service.
path());
725 _service.
name(), _service.
icon(), window, asn);
735 if (!appSupportedProtocols.contains(
"KIO")) {
736 for (KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it) {
737 const KUrl url = *it;
739 kDebug(7010) <<
"Looking at url=" << url <<
" supported=" << supported;
743 if (localURL != url) {
745 kDebug(7010) <<
"Changed to " << localURL;
755 class SecureMessageDialog :
public KDialog
758 SecureMessageDialog(
QWidget *parent) :
KDialog(parent), m_textEdit(0)
762 void setTextEdit(QPlainTextEdit *textEdit)
764 m_textEdit = textEdit;
768 virtual void showEvent(QShowEvent* e)
772 KDialog::showEvent(e);
781 QRect curRect(m_textEdit->rect());
782 QFontMetrics metrics(fontMetrics());
783 curRect.setHeight(5 * metrics.lineSpacing());
784 curRect.setWidth(qMax(curRect.width(), 300));
786 QString text(m_textEdit->toPlainText());
787 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
791 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
792 if(curRect.height() < m_textEdit->height()) {
793 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
794 m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
797 m_textEdit->setMinimumSize(curRect.size() + fudge);
798 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
803 QPlainTextEdit *m_textEdit;
814 QFile desktopFile(fileName);
815 if (!desktopFile.open(QFile::ReadOnly)) {
816 kError(7010) <<
"Error opening service" << fileName << desktopFile.errorString();
820 QByteArray
header = desktopFile.peek(2);
821 if (header.size() == 0) {
822 kError(7010) <<
"Error inspecting service" << fileName << desktopFile.errorString();
826 if (header !=
"#!") {
830 if (!saveFile.
open()) {
831 kError(7010) <<
"Unable to open replacement file for" << fileName << saveFile.
errorString();
835 QByteArray shebang(
"#!/usr/bin/env xdg-open\n");
836 if (saveFile.write(shebang) != shebang.size()) {
837 kError(7010) <<
"Error occurred adding header for" << fileName << saveFile.
errorString();
843 QByteArray desktopData(desktopFile.readAll());
844 if (desktopData.isEmpty()) {
845 kError(7010) <<
"Unable to read service" << fileName << desktopFile.errorString();
850 if (saveFile.write(desktopData) != desktopData.size()) {
858 kError(7010) <<
"Error committing changes to service" << fileName << saveFile.
errorString();
862 if (!desktopFile.open(QFile::ReadOnly)) {
863 kError(7010) <<
"Error re-opening service" << fileName << desktopFile.errorString();
870 if (!desktopFile.setPermissions(QFile::ExeUser | desktopFile.permissions())) {
871 kError(7010) <<
"Unable to change permissions for" << fileName << desktopFile.errorString();
892 SecureMessageDialog *baseDialog =
new SecureMessageDialog(window);
895 baseDialog->setButtonGuiItem(
KDialog::Ok, continueItem);
898 baseDialog->setCaption(
i18nc(
"Warning about executing unknown .desktop file",
"Warning"));
903 QHBoxLayout *mainLayout =
new QHBoxLayout(baseWidget);
907 mainLayout->addWidget(iconLabel);
908 iconLabel->setPixmap(warningIcon);
910 QVBoxLayout *contentLayout =
new QVBoxLayout;
911 QString warningMessage =
i18nc(
"program name follows in a line edit below",
912 "This will start the program:");
915 contentLayout->addWidget(message);
921 QPlainTextEdit *textEdit =
new QPlainTextEdit(baseWidget);
922 textEdit->setPlainText(program);
923 textEdit->setReadOnly(
true);
924 contentLayout->addWidget(textEdit);
926 QLabel *footerLabel =
new QLabel(
i18n(
"If you do not trust this program, click Cancel"));
927 contentLayout->addWidget(footerLabel);
928 contentLayout->addStretch(0);
930 mainLayout->addLayout(contentLayout);
932 baseDialog->setMainWidget(baseWidget);
933 baseDialog->setTextEdit(textEdit);
937 QSize screenSize = QApplication::desktop()->screen()->size();
938 baseDialog->resize(screenSize.width() / 4, 50);
939 baseDialog->setMaximumHeight(screenSize.height() / 3);
940 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
942 int result = baseDialog->exec();
943 if (result != KDialog::Accepted) {
954 if(serviceName.isEmpty())
959 i18n(
"Unable to make the service %1 executable, aborting execution", serviceName)
980 KUrl::List::ConstIterator it = _urls.begin();
981 for (; it != _urls.end(); ++it) {
987 if (tempFiles || _service.
entryPath().isEmpty() || !suggestedFileName.isEmpty()) {
988 return runTempService(_service, _urls, window, tempFiles, suggestedFileName, asn);
993 if (!_urls.isEmpty()) {
994 kDebug(7010) <<
"First url " << _urls.first().url();
1003 QByteArray myasn = asn;
1005 if (window != NULL) {
1006 if (myasn.isEmpty()) {
1028 kDebug(7010) <<
"startServiceByDesktopPath worked fine";
1034 const QString& _icon,
const QByteArray& asn)
1038 return run(*service, _urls, window,
false,
QString(), asn);
1048 if (cmd.isEmpty()) {
1049 kWarning() <<
"Command was empty, nothing to run";
1054 if (args.isEmpty()) {
1055 kWarning() <<
"Command could not be parsed.";
1059 const QString bin = args.first();
1060 return KRun::runCommand(cmd, bin, bin , window, QByteArray(), workingDirectory);
1069 QWidget* window,
const QByteArray& asn,
const QString& workingDirectory)
1071 kDebug(7010) <<
"runCommand " << cmd <<
"," << execName;
1074 if (workingDirectory.isEmpty()) {
1079 proc->setWorkingDirectory(workingDirectory);
1086 iconName, window, asn);
1090 bool showProgressInfo,
const QByteArray& asn)
1093 d->
m_timer.setObjectName(
"KRun::timer");
1094 d->
m_timer.setSingleShot(
true);
1095 d->
init(url, window, mode, isLocalFile, showProgressInfo, asn);
1099 bool showProgressInfo,
const QByteArray& asn)
1129 kDebug(7010) <<
"INIT called";
1161 KDE_struct_stat buff;
1165 i18n(
"<qt>Unable to run the command specified. "
1166 "The file or folder <b>%1</b> does not exist.</qt>" ,
1174 d->
m_mode = buff.st_mode;
1179 kDebug(7010) <<
"MIME TYPE is " << mime->
name();
1181 mime->
is(QLatin1String(
"text/html")) ||
1182 mime->
is(QLatin1String(
"application/xml")))) {
1192 kDebug(7010) <<
"Helper protocol";
1194 if (exec.isEmpty()) {
1207 if (S_ISDIR(d->
m_mode)) {
1221 kDebug(7010) <<
"Testing directory (stating)";
1227 connect(job, SIGNAL(result(
KJob*)),
1246 urls.append(m_strURL);
1247 if (_exec.startsWith(
'!')) {
1258 if (service && q->run(*service, urls, m_window,
false,
QString(), m_asn)) {
1276 kDebug(7010) <<
"Scanfile: MIME TYPE is " << mime->
name();
1287 kError(7010) <<
"#### NO SUPPORT FOR READING!";
1298 connect(job, SIGNAL(result(
KJob*)),
1303 kDebug(7010) <<
" Job " << job <<
" is about getting from " << d->
m_strURL.
url();
1310 kDebug(7010) <<
this <<
" slotTimeout called";
1345 const int errCode = job->
error();
1364 kDebug(7010) <<
"Finished";
1368 kFatal() <<
"job is a " <<
typeid(*job).name() <<
" should be a StatJob";
1376 if (S_ISDIR(mode)) {
1388 if (!knownMimeType.isEmpty()) {
1405 if (mimetype.isEmpty()) {
1406 kWarning(7010) <<
"get() didn't emit a mimetype! Probably a kioslave bug, please check the implementation of" <<
url().
protocol();
1415 const int errCode = job->
error();
1452 kDebug(7010) <<
"Resulting mime type is " << type;
1487 kWarning(7010) <<
"Unknown mimetype " << type;
1489 if (mime && mime->
is(
"application/x-desktop") && !d->
m_localPath.isEmpty()) {
1582 return (serviceType ==
"application/x-desktop" ||
1583 serviceType ==
"application/x-executable" ||
1584 serviceType ==
"application/x-ms-dos-executable" ||
1585 serviceType ==
"application/x-shellscript");
1630 #ifndef KDE_NO_DEPRECATED
1637 #ifndef KDE_NO_DEPRECATED
1644 #ifndef KDE_NO_DEPRECATED
1651 #ifndef KDE_NO_DEPRECATED
1663 #ifndef KDE_NO_DEPRECATED
1670 #ifndef KDE_NO_DEPRECATED
1712 KProcessRunner::KProcessRunner(
KProcess * p,
const QString & executable)
1720 m_executable = executable;
1721 connect(process, SIGNAL(finished(
int,QProcess::ExitStatus)),
1725 if (!process->waitForStarted()) {
1733 m_pid = process->
pid();
1748 void KProcessRunner::terminateStartupNotification()
1764 kDebug(7010) << m_executable <<
"exitCode=" << exitCode <<
"exitStatus=" << exitStatus;
1765 Q_UNUSED(exitStatus);
1767 terminateStartupNotification();
1768 if (exitCode != 0 && !m_executable.isEmpty()) {
1781 kDebug() << process->readAllStandardError();
1788 #include "krun_p.moc"