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>
83 #elif defined(Q_WS_WIN)
84 #include <QDesktopServices>
89 m_showingDialog(false)
106 if (file.isExecutable()) {
107 KMimeType::Ptr mimeType = KMimeType::mimeType(mimetype, KMimeType::ResolveAliases);
108 if (mimeType && (mimeType->is(QLatin1String(
"application/x-executable")) ||
110 mimeType->is(QLatin1String(
"application/x-ms-dos-executable")) ||
112 mimeType->is(QLatin1String(
"application/x-executable-script")))
126 if (_mimetype == QLatin1String(
"inode/directory-locked")) {
128 i18n(
"<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", Qt::escape(u.
prettyUrl())));
131 else if (_mimetype == QLatin1String(
"application/x-desktop")) {
138 if (KAuthorized::authorize(
"shell_access")) {
146 else if (_mimetype == QLatin1String(
"application/x-executable")) {
151 if (!runExecutables) {
155 if (!KAuthorized::authorize(
"shell_access")) {
162 i18n(
"<qt>The file <b>%1</b> is an executable program. "
163 "For safety it will not be started.</qt>", Qt::escape(u.
prettyUrl())));
168 i18n(
"<qt>You do not have permission to run <b>%1</b>.</qt>", Qt::escape(u.
prettyUrl())));
181 return QDesktopServices::openUrl(u);
190 return KRun::run(*offer, lst, window, tempFile, suggestedFileName, asn);
196 if (!KAuthorized::authorizeKAction(
"openwith")) {
198 i18n(
"You are not authorized to select an application to open this file."));
203 KConfigGroup cfgGroup(KGlobal::config(),
"KOpenWithDialog Settings");
204 if (cfgGroup.
readEntry(
"Native",
true)) {
206 suggestedFileName, asn);
213 kDebug(7010) <<
"No service set, running " << l.
text();
216 return KRun::run(*service, lst, window, tempFiles, suggestedFileName, asn);
221 #ifndef KDE_NO_DEPRECATED
225 if (_str.isEmpty()) {
229 _str.replace(q,
"'\\''").prepend(q).append(q);
240 bool hasUrls: 1, hasSpec: 1;
252 uint option = str[pos + 1].unicode();
255 ret << service.name().replace(
'%',
"%%");
258 ret << service.entryPath().replace(
'%',
"%%");
261 ret <<
"--icon" << service.icon().replace(
'%',
"%%");
265 kWarning() <<
"-miniicon isn't supported anymore (service"
266 << service.name() <<
')';
309 ret << ((url.
isLocalFile() && url.fragment().isNull() && url.encodedQuery().isNull()) ?
316 ret << QDir::toNativeSeparators(url.
toLocalFile());
333 uint option = str[pos + 1].unicode();
340 if (urls.isEmpty()) {
342 kDebug() <<
"No URLs supplied to single-URL service" << str;
345 else if (urls.count() > 1) {
346 kWarning() << urls.count() <<
"URLs supplied to single-URL service" << str;
349 subst(option, urls.first(), ret);
357 for (KUrl::List::ConstIterator it = urls.begin(); it != urls.end(); ++it)
358 subst(option, *it, ret);
374 KRunMX1 mx1(_service);
376 if (mx1.expandMacrosShellQuote(exec) && !mx1.hasUrls) {
377 Q_ASSERT(supportedProtocols.isEmpty());
380 if (supportedProtocols.isEmpty()) {
383 if (categories.contains(
"KDE")
385 || _service.entryPath().isEmpty() ) {
386 supportedProtocols.append(
"KIO");
389 supportedProtocols.append(
"http");
390 supportedProtocols.append(
"https");
391 supportedProtocols.append(
"ftp");
401 if (supportedProtocols.contains(
"KIO"))
409 if (exec.isEmpty()) {
410 kWarning() <<
"KRun: no Exec field in `" << _service.entryPath() <<
"' !";
415 bool appHasTempFileOption;
417 KRunMX1 mx1(_service);
420 if (!mx1.expandMacrosShellQuote(exec)) {
421 kWarning() <<
"KRun: syntax error in command" << _service.
exec() <<
", service" << _service.name();
428 appHasTempFileOption = tempFiles && _service.
property(
"X-KDE-HasTempFileOption").toBool();
429 if (tempFiles && !appHasTempFileOption && _urls.size()) {
431 Q_ASSERT(!kioexec.isEmpty());
432 result << kioexec <<
"--tempfiles" << exec;
433 if (!suggestedFileName.isEmpty()) {
434 result <<
"--suggestedfilename";
442 bool useKioexec =
false;
444 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
447 kDebug(7010) <<
"non-local files, application does not support urls, using kioexec";
452 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
455 kDebug(7010) <<
"application does not support url, using kioexec:" << *it;
462 Q_ASSERT(!kioexec.isEmpty());
465 result <<
"--tempfiles";
467 if (!suggestedFileName.isEmpty()) {
468 result <<
"--suggestedfilename";
476 if (appHasTempFileOption) {
477 exec +=
" --tempfile";
488 mx2.expandMacrosShellQuote(exec);
510 if (terminal ==
"konsole") {
511 if (!_service.
path().isEmpty()) {
512 terminal +=
" --workdir " + KShell::quoteArg(_service.
path());
514 terminal +=
" -caption=%c %i %m";
518 if (!mx1.expandMacrosShellQuote(terminal)) {
519 kWarning() <<
"KRun: syntax error in command" << terminal <<
", service" << _service.name();
522 mx2.expandMacrosShellQuote(terminal);
523 result = KShell::splitArgs(terminal);
528 QStringList execlist = KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
529 if (err == KShell::NoError && !execlist.isEmpty()) {
533 if (!exePath.isEmpty()) {
534 execlist[0] = exePath;
545 result << _service.
username() <<
"-c";
546 if (err == KShell::FoundMeta) {
547 exec =
"/bin/sh -c " + KShell::quoteArg(exec);
550 exec = KShell::joinArgs(execlist);
555 if (err == KShell::FoundMeta) {
556 result <<
"/bin/sh" <<
"-c" << exec;
570 const QStringList args = KShell::splitArgs(execLine);
571 for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
572 if (!(*it).contains(
'=')) {
574 return removePath ? (*it).mid((*it).lastIndexOf(
'/') + 1) : *it;
581 const QByteArray& asn)
583 if (window != NULL) {
584 window = window->topLevelWidget();
586 if (service && !service->entryPath().isEmpty()
589 kWarning() <<
"No authorization to execute " << service->entryPath();
596 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
601 if (startup_notify) {
603 id.setupStartupEnv();
607 if (!userVisibleName.isEmpty()) {
610 else if (service && !service->name().isEmpty()) {
614 if (!iconName.isEmpty()) {
617 else if (service && !service->
icon().isEmpty()) {
620 if (!wmclass.isEmpty()) {
630 if(service && !service->entryPath().isEmpty())
635 if (startup_notify && pid) {
643 Q_UNUSED(userVisibleName);
654 if (service && service->
property(
"StartupNotify").isValid()) {
655 silent = !service->
property(
"StartupNotify").toBool();
656 wmclass = service->
property(
"StartupWMClass").toString().toLatin1();
658 else if (service && service->
property(
"X-KDE-StartupNotify").isValid()) {
659 silent = !service->
property(
"X-KDE-StartupNotify").toBool();
660 wmclass = service->
property(
"X-KDE-WMClass").toString().toLatin1();
678 #else // That unfortunately doesn't work, when the launched non-compliant application
684 if (silent_arg != NULL) {
685 *silent_arg = silent;
687 if (wmclass_arg != NULL) {
688 *wmclass_arg = wmclass;
696 if (!_urls.isEmpty()) {
697 kDebug(7010) <<
"runTempService: first url " << _urls.first().url();
707 KUrl::List::ConstIterator it = _urls.begin();
708 while (++it != _urls.end()) {
710 singleUrl.append(*it);
711 runTempService(_service, singleUrl, window, tempFiles, suggestedFileName, QByteArray());
714 singleUrl.append(_urls.first());
720 if (args.isEmpty()) {
724 kDebug(7010) <<
"runTempService: KProcess args=" << args;
729 if (!_service.
path().isEmpty()) {
730 proc->setWorkingDirectory(_service.
path());
734 _service.name(), _service.
icon(),
window, asn);
744 if (!appSupportedProtocols.contains(
"KIO")) {
745 for (KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it) {
746 const KUrl url = *it;
748 kDebug(7010) <<
"Looking at url=" << url <<
" supported=" << supported;
752 if (localURL != url) {
754 kDebug(7010) <<
"Changed to " << localURL;
764 class SecureMessageDialog :
public KDialog
767 SecureMessageDialog(
QWidget *parent) :
KDialog(parent), m_textEdit(0)
771 void setTextEdit(QPlainTextEdit *textEdit)
773 m_textEdit = textEdit;
777 virtual void showEvent(QShowEvent* e)
781 KDialog::showEvent(e);
790 QRect curRect(m_textEdit->rect());
791 QFontMetrics metrics(fontMetrics());
792 curRect.setHeight(5 * metrics.lineSpacing());
793 curRect.setWidth(qMax(curRect.width(), 300));
795 QString text(m_textEdit->toPlainText());
796 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
800 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
801 if(curRect.height() < m_textEdit->height()) {
802 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
803 m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
806 m_textEdit->setMinimumSize(curRect.size() + fudge);
807 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
812 QPlainTextEdit *m_textEdit;
823 QFile desktopFile(fileName);
824 if (!desktopFile.open(QFile::ReadOnly)) {
825 kError(7010) <<
"Error opening service" << fileName << desktopFile.errorString();
829 QByteArray
header = desktopFile.peek(2);
830 if (header.size() == 0) {
831 kError(7010) <<
"Error inspecting service" << fileName << desktopFile.errorString();
835 if (header !=
"#!") {
839 if (!saveFile.
open()) {
840 kError(7010) <<
"Unable to open replacement file for" << fileName << saveFile.
errorString();
844 QByteArray shebang(
"#!/usr/bin/env xdg-open\n");
845 if (saveFile.write(shebang) != shebang.size()) {
846 kError(7010) <<
"Error occurred adding header for" << fileName << saveFile.
errorString();
852 QByteArray desktopData(desktopFile.readAll());
853 if (desktopData.isEmpty()) {
854 kError(7010) <<
"Unable to read service" << fileName << desktopFile.errorString();
859 if (saveFile.write(desktopData) != desktopData.size()) {
860 kError(7010) <<
"Error copying service" << fileName << saveFile.
errorString();
867 kError(7010) <<
"Error committing changes to service" << fileName << saveFile.
errorString();
871 if (!desktopFile.open(QFile::ReadOnly)) {
872 kError(7010) <<
"Error re-opening service" << fileName << desktopFile.errorString();
879 if (!desktopFile.setPermissions(QFile::ExeUser | desktopFile.permissions())) {
880 kError(7010) <<
"Unable to change permissions for" << fileName << desktopFile.errorString();
893 if (!KAuthorized::authorize(
"run_desktop_files")) {
894 kWarning() <<
"No authorization to execute " << service.entryPath();
899 KGuiItem continueItem = KStandardGuiItem::cont();
901 SecureMessageDialog *baseDialog =
new SecureMessageDialog(window);
903 baseDialog->setButtons(KDialog::Ok | KDialog::Cancel);
904 baseDialog->setButtonGuiItem(KDialog::Ok, continueItem);
905 baseDialog->setDefaultButton(KDialog::Cancel);
906 baseDialog->setButtonFocus(KDialog::Cancel);
907 baseDialog->setCaption(
i18nc(
"Warning about executing unknown .desktop file",
"Warning"));
912 QHBoxLayout *mainLayout =
new QHBoxLayout(baseWidget);
916 mainLayout->addWidget(iconLabel);
917 iconLabel->setPixmap(warningIcon);
919 QVBoxLayout *contentLayout =
new QVBoxLayout;
920 QString warningMessage =
i18nc(
"program name follows in a line edit below",
921 "This will start the program:");
924 contentLayout->addWidget(message);
930 QPlainTextEdit *textEdit =
new QPlainTextEdit(baseWidget);
931 textEdit->setPlainText(program);
932 textEdit->setReadOnly(
true);
933 contentLayout->addWidget(textEdit);
935 QLabel *footerLabel =
new QLabel(
i18n(
"If you do not trust this program, click Cancel"));
936 contentLayout->addWidget(footerLabel);
937 contentLayout->addStretch(0);
939 mainLayout->addLayout(contentLayout);
941 baseDialog->setMainWidget(baseWidget);
942 baseDialog->setTextEdit(textEdit);
946 QSize screenSize = QApplication::desktop()->screen()->size();
947 baseDialog->resize(screenSize.width() / 4, 50);
948 baseDialog->setMaximumHeight(screenSize.height() / 3);
949 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
951 int result = baseDialog->exec();
952 if (result != KDialog::Accepted) {
962 QString serviceName = service.name();
963 if(serviceName.isEmpty())
968 i18n(
"Unable to make the service %1 executable, aborting execution", serviceName)
980 if (!_service.entryPath().isEmpty() &&
989 KUrl::List::ConstIterator it = _urls.begin();
990 for (; it != _urls.end(); ++it) {
996 if (tempFiles || _service.entryPath().isEmpty() || !suggestedFileName.isEmpty()) {
997 return runTempService(_service, _urls, window, tempFiles, suggestedFileName, asn);
1000 kDebug(7010) <<
"KRun::run " << _service.entryPath();
1002 if (!_urls.isEmpty()) {
1003 kDebug(7010) <<
"First url " << _urls.first().url();
1012 QByteArray myasn = asn;
1014 if (window != NULL) {
1015 if (myasn.isEmpty()) {
1037 kDebug(7010) <<
"startServiceByDesktopPath worked fine";
1043 const QString& _icon,
const QByteArray& asn)
1047 return run(*service, _urls, window,
false,
QString(), asn);
1057 if (cmd.isEmpty()) {
1058 kWarning() <<
"Command was empty, nothing to run";
1063 if (args.isEmpty()) {
1064 kWarning() <<
"Command could not be parsed.";
1068 const QString bin = args.first();
1069 return KRun::runCommand(cmd, bin, bin , window, QByteArray(), workingDirectory);
1080 kDebug(7010) <<
"runCommand " << cmd <<
"," << execName;
1083 if (!workingDirectory.isEmpty()) {
1084 proc->setWorkingDirectory(workingDirectory);
1095 bool showProgressInfo,
const QByteArray& asn)
1098 d->
m_timer.setObjectName(
"KRun::timer");
1099 d->
m_timer.setSingleShot(
true);
1100 d->
init(url, window, mode, isLocalFile, showProgressInfo, asn);
1104 bool showProgressInfo,
const QByteArray& asn)
1134 kDebug(7010) <<
"INIT called";
1145 if (!KAuthorized::authorizeUrlAction(
"open",
KUrl(), d->
m_strURL)) {
1166 KDE_struct_stat buff;
1170 i18n(
"<qt>Unable to run the command specified. "
1171 "The file or folder <b>%1</b> does not exist.</qt>" ,
1179 d->
m_mode = buff.st_mode;
1184 kDebug(7010) <<
"MIME TYPE is " << mime->name();
1186 (mime->is(QLatin1String(
"text/html")) ||
1187 mime->is(QLatin1String(
"application/xhtml+xml")))) {
1207 kDebug(7010) <<
"Helper protocol";
1209 if (exec.isEmpty()) {
1222 if (S_ISDIR(d->
m_mode)) {
1236 kDebug(7010) <<
"Testing directory (stating)";
1242 connect(job, SIGNAL(result(
KJob*)),
1261 urls.append(m_strURL);
1262 if (_exec.startsWith(
'!')) {
1273 if (service && q->run(*service, urls, m_window,
false,
QString(), m_asn)) {
1291 kDebug(7010) <<
"Scanfile: MIME TYPE is " << mime->name();
1302 kError(7010) <<
"#### NO SUPPORT FOR READING!";
1313 connect(job, SIGNAL(result(
KJob*)),
1318 kDebug(7010) <<
" Job " << job <<
" is about getting from " << d->
m_strURL.
url();
1325 kDebug(7010) <<
this <<
" slotTimeout called";
1360 const int errCode = job->error();
1366 kError(7010) <<
this <<
"ERROR" << job->error() << job->errorString();
1367 job->uiDelegate()->showErrorMessage();
1379 kDebug(7010) <<
"Finished";
1383 kFatal() <<
"job is a " <<
typeid(*job).name() <<
" should be a StatJob";
1391 if (S_ISDIR(mode)) {
1403 if (!knownMimeType.isEmpty()) {
1420 if (mimetype.isEmpty()) {
1421 kWarning(7010) <<
"get() didn't emit a mimetype! Probably a kioslave bug, please check the implementation of" <<
url().
protocol();
1430 const int errCode = job->error();
1436 kError(7010) <<
this <<
"ERROR (stat):" << job->error() <<
' ' << job->errorString();
1437 job->uiDelegate()->showErrorMessage();
1467 kDebug(7010) <<
"Resulting mime type is " << type;
1500 KMimeType::Ptr mime = KMimeType::mimeType(type, KMimeType::ResolveAliases);
1502 kWarning(7010) <<
"Unknown mimetype " << type;
1504 if (mime && mime->is(
"application/x-desktop") && !d->
m_localPath.isEmpty()) {
1602 return (serviceType ==
"application/x-desktop" ||
1603 serviceType ==
"application/x-executable" ||
1604 serviceType ==
"application/x-ms-dos-executable" ||
1605 serviceType ==
"application/x-shellscript");
1650 #ifndef KDE_NO_DEPRECATED
1657 #ifndef KDE_NO_DEPRECATED
1664 #ifndef KDE_NO_DEPRECATED
1671 #ifndef KDE_NO_DEPRECATED
1683 #ifndef KDE_NO_DEPRECATED
1690 #ifndef KDE_NO_DEPRECATED
1732 KProcessRunner::KProcessRunner(
KProcess * p,
const QString & executable)
1740 m_executable = executable;
1741 connect(process, SIGNAL(finished(
int,QProcess::ExitStatus)),
1745 if (!process->waitForStarted()) {
1753 m_pid = process->
pid();
1768 void KProcessRunner::terminateStartupNotification()
1784 kDebug(7010) << m_executable <<
"exitCode=" << exitCode <<
"exitStatus=" << exitStatus;
1785 Q_UNUSED(exitStatus);
1787 terminateStartupNotification();
1788 if (exitCode != 0 && !m_executable.isEmpty()) {
1801 kDebug() << process->readAllStandardError();
1808 #include "krun_p.moc"