00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "krun.h"
00023 #include "krun_p.h"
00024
00025 #include <config.h>
00026
00027 #include <assert.h>
00028 #include <stdlib.h>
00029 #include <string.h>
00030 #include <unistd.h>
00031 #include <typeinfo>
00032 #include <sys/stat.h>
00033
00034 #include <QtGui/QWidget>
00035 #include <QtGui/QLabel>
00036 #include <QtGui/QVBoxLayout>
00037 #include <QtGui/QHBoxLayout>
00038 #include <QtGui/QPlainTextEdit>
00039 #include <QtGui/QApplication>
00040 #include <QtGui/QDesktopWidget>
00041
00042 #include "kmimetypetrader.h"
00043 #include "kmimetype.h"
00044 #include "kio/jobclasses.h"
00045 #include "kio/job.h"
00046 #include "kio/jobuidelegate.h"
00047 #include "kio/global.h"
00048 #include "kio/scheduler.h"
00049 #include "kio/netaccess.h"
00050 #include "kfile/kopenwithdialog.h"
00051 #include "kfile/krecentdocument.h"
00052 #include "kdesktopfileactions.h"
00053
00054 #include <kauthorized.h>
00055 #include <kmessageboxwrapper.h>
00056 #include <kurl.h>
00057 #include <kglobal.h>
00058 #include <ktoolinvocation.h>
00059 #include <kauthorized.h>
00060 #include <kdebug.h>
00061 #include <klocale.h>
00062 #include <kprotocolmanager.h>
00063 #include <kstandarddirs.h>
00064 #include <kprocess.h>
00065 #include <QtCore/QFile>
00066 #include <QtCore/QFileInfo>
00067 #include <QtCore/QTextIStream>
00068 #include <QtCore/QDate>
00069 #include <QtCore/QRegExp>
00070 #include <kdesktopfile.h>
00071 #include <kmacroexpander.h>
00072 #include <kshell.h>
00073 #include <QTextDocument>
00074 #include <kde_file.h>
00075 #include <kconfiggroup.h>
00076 #include <kdialog.h>
00077 #include <kstandardguiitem.h>
00078 #include <kguiitem.h>
00079 #include <ksavefile.h>
00080
00081 #ifdef Q_WS_X11
00082 #include <kwindowsystem.h>
00083 #endif
00084
00085 KRun::KRunPrivate::KRunPrivate(KRun *parent)
00086 : q(parent),
00087 m_showingDialog(false)
00088 {
00089 }
00090
00091 void KRun::KRunPrivate::startTimer()
00092 {
00093 m_timer.start(0);
00094 }
00095
00096
00097
00098 bool KRun::isExecutableFile(const KUrl& url, const QString &mimetype)
00099 {
00100 if (!url.isLocalFile()) {
00101 return false;
00102 }
00103 QFileInfo file(url.toLocalFile());
00104 if (file.isExecutable()) {
00105 KMimeType::Ptr mimeType = KMimeType::mimeType(mimetype, KMimeType::ResolveAliases);
00106 if (mimeType && (mimeType->is(QLatin1String("application/x-executable")) ||
00107 #ifdef Q_WS_WIN
00108 mimeType->is(QLatin1String("application/x-ms-dos-executable")) ||
00109 #endif
00110 mimeType->is(QLatin1String("application/x-executable-script")))
00111 )
00112 {
00113 return true;
00114 }
00115 }
00116 return false;
00117 }
00118
00119
00120 bool KRun::runUrl(const KUrl& u, const QString& _mimetype, QWidget* window, bool tempFile, bool runExecutables, const QString& suggestedFileName, const QByteArray& asn)
00121 {
00122 bool noRun = false;
00123 bool noAuth = false;
00124 if (_mimetype == QLatin1String("inode/directory-locked")) {
00125 KMessageBoxWrapper::error(window,
00126 i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", Qt::escape(u.prettyUrl())));
00127 return false;
00128 }
00129 else if (_mimetype == QLatin1String("application/x-desktop")) {
00130 if (u.isLocalFile() && runExecutables) {
00131 return KDesktopFileActions::run(u, true);
00132 }
00133 }
00134 else if (isExecutableFile(u, _mimetype)) {
00135 if (u.isLocalFile() && runExecutables) {
00136 if (KAuthorized::authorize("shell_access")) {
00137 return (KRun::runCommand(KShell::quoteArg(u.toLocalFile()), QString(), QString(), window, asn));
00138
00139 }
00140 else {
00141 noAuth = true;
00142 }
00143 }
00144 else if (_mimetype == QLatin1String("application/x-executable")) {
00145 noRun = true;
00146 }
00147 }
00148 else if (isExecutable(_mimetype)) {
00149 if (!runExecutables) {
00150 noRun = true;
00151 }
00152
00153 if (!KAuthorized::authorize("shell_access")) {
00154 noAuth = true;
00155 }
00156 }
00157
00158 if (noRun) {
00159 KMessageBox::sorry(window,
00160 i18n("<qt>The file <b>%1</b> is an executable program. "
00161 "For safety it will not be started.</qt>", Qt::escape(u.prettyUrl())));
00162 return false;
00163 }
00164 if (noAuth) {
00165 KMessageBoxWrapper::error(window,
00166 i18n("<qt>You do not have permission to run <b>%1</b>.</qt>", Qt::escape(u.prettyUrl())));
00167 return false;
00168 }
00169
00170 KUrl::List lst;
00171 lst.append(u);
00172
00173 KService::Ptr offer = KMimeTypeTrader::self()->preferredService(_mimetype);
00174
00175 if (!offer) {
00176
00177
00178
00179 return displayOpenWithDialog(lst, window, tempFile, suggestedFileName, asn);
00180 }
00181
00182 return KRun::run(*offer, lst, window, tempFile, suggestedFileName, asn);
00183 }
00184
00185 bool KRun::displayOpenWithDialog(const KUrl::List& lst, QWidget* window, bool tempFiles,
00186 const QString& suggestedFileName, const QByteArray& asn)
00187 {
00188 if (!KAuthorized::authorizeKAction("openwith")) {
00189 KMessageBox::sorry(window,
00190 i18n("You are not authorized to select an application to open this file."));
00191 return false;
00192 }
00193
00194 #ifdef Q_WS_WIN
00195 KConfigGroup cfgGroup(KGlobal::config(), "KOpenWithDialog Settings");
00196 if (cfgGroup.readEntry("Native", true)) {
00197 return KRun::KRunPrivate::displayNativeOpenWithDialog(lst, window, tempFiles,
00198 suggestedFileName, asn);
00199 }
00200 #endif
00201 KOpenWithDialog l(lst, i18n("Open with:"), QString(), window);
00202 if (l.exec()) {
00203 KService::Ptr service = l.service();
00204 if (service) {
00205 return KRun::run(*service, lst, window, tempFiles, suggestedFileName, asn);
00206 }
00207
00208 kDebug(7010) << "No service set, running " << l.text();
00209 return KRun::run(l.text(), lst, window, false, suggestedFileName, asn);
00210 }
00211 return false;
00212 }
00213
00214 void KRun::shellQuote(QString &_str)
00215 {
00216
00217 if (_str.isEmpty()) {
00218 return;
00219 }
00220 QChar q('\'');
00221 _str.replace(q, "'\\''").prepend(q).append(q);
00222 }
00223
00224
00225 class KRunMX1 : public KMacroExpanderBase
00226 {
00227 public:
00228 KRunMX1(const KService &_service) :
00229 KMacroExpanderBase('%'), hasUrls(false), hasSpec(false), service(_service) {}
00230
00231 bool hasUrls: 1, hasSpec: 1;
00232
00233 protected:
00234 virtual int expandEscapedMacro(const QString &str, int pos, QStringList &ret);
00235
00236 private:
00237 const KService &service;
00238 };
00239
00240 int
00241 KRunMX1::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
00242 {
00243 uint option = str[pos + 1].unicode();
00244 switch (option) {
00245 case 'c':
00246 ret << service.name().replace('%', "%%");
00247 break;
00248 case 'k':
00249 ret << service.entryPath().replace('%', "%%");
00250 break;
00251 case 'i':
00252 ret << "-icon" << service.icon().replace('%', "%%");
00253 break;
00254 case 'm':
00255
00256 kWarning() << "-miniicon isn't supported anymore (service"
00257 << service.name() << ')';
00258 break;
00259 case 'u':
00260 case 'U':
00261 hasUrls = true;
00262
00263 case 'f':
00264 case 'F':
00265 case 'n':
00266 case 'N':
00267 case 'd':
00268 case 'D':
00269 case 'v':
00270 hasSpec = true;
00271
00272 default:
00273 return -2;
00274 }
00275 return 2;
00276 }
00277
00278 class KRunMX2 : public KMacroExpanderBase
00279 {
00280 public:
00281 KRunMX2(const KUrl::List &_urls) :
00282 KMacroExpanderBase('%'), ignFile(false), urls(_urls) {}
00283
00284 bool ignFile: 1;
00285
00286 protected:
00287 virtual int expandEscapedMacro(const QString &str, int pos, QStringList &ret);
00288
00289 private:
00290 void subst(int option, const KUrl &url, QStringList &ret);
00291
00292 const KUrl::List &urls;
00293 };
00294
00295 void
00296 KRunMX2::subst(int option, const KUrl &url, QStringList &ret)
00297 {
00298 switch (option) {
00299 case 'u':
00300 ret << ((url.isLocalFile() && url.fragment().isNull() && url.encodedQuery().isNull()) ?
00301 url.toLocalFile() : url.url());
00302 break;
00303 case 'd':
00304 ret << url.directory();
00305 break;
00306 case 'f':
00307 ret << url.path();
00308 break;
00309 case 'n':
00310 ret << url.fileName();
00311 break;
00312 case 'v':
00313 if (url.isLocalFile() && QFile::exists(url.toLocalFile())) {
00314 ret << KDesktopFile(url.path()).desktopGroup().readEntry("Dev");
00315 }
00316 break;
00317 }
00318 return;
00319 }
00320
00321 int
00322 KRunMX2::expandEscapedMacro(const QString &str, int pos, QStringList &ret)
00323 {
00324 uint option = str[pos + 1].unicode();
00325 switch (option) {
00326 case 'f':
00327 case 'u':
00328 case 'n':
00329 case 'd':
00330 case 'v':
00331 if (urls.isEmpty()) {
00332 if (!ignFile) {
00333 kDebug() << "No URLs supplied to single-URL service" << str;
00334 }
00335 }
00336 else if (urls.count() > 1) {
00337 kWarning() << urls.count() << "URLs supplied to single-URL service" << str;
00338 }
00339 else {
00340 subst(option, urls.first(), ret);
00341 }
00342 break;
00343 case 'F':
00344 case 'U':
00345 case 'N':
00346 case 'D':
00347 option += 'a' - 'A';
00348 for (KUrl::List::ConstIterator it = urls.begin(); it != urls.end(); ++it)
00349 subst(option, *it, ret);
00350 break;
00351 case '%':
00352 ret = QStringList(QLatin1String("%"));
00353 break;
00354 default:
00355 return -2;
00356 }
00357 return 2;
00358 }
00359
00360 QStringList KRun::processDesktopExec(const KService &_service, const KUrl::List& _urls, bool tempFiles, const QString& suggestedFileName)
00361 {
00362 QString exec = _service.exec();
00363 if (exec.isEmpty()) {
00364 kWarning() << "KRun: no Exec field in `" << _service.entryPath() << "' !";
00365 return QStringList();
00366 }
00367
00368 QStringList result;
00369 bool appHasTempFileOption;
00370
00371 KRunMX1 mx1(_service);
00372 KRunMX2 mx2(_urls);
00373
00374 if (!mx1.expandMacrosShellQuote(exec)) {
00375 kWarning() << "KRun: syntax error in command" << _service.exec() << ", service" << _service.name();
00376 return QStringList();
00377 }
00378
00379
00380
00381
00382 appHasTempFileOption = tempFiles && _service.property("X-KDE-HasTempFileOption").toBool();
00383 if (tempFiles && !appHasTempFileOption && _urls.size()) {
00384 const QString kioexec = KStandardDirs::findExe("kioexec");
00385 Q_ASSERT(!kioexec.isEmpty());
00386 result << kioexec << "--tempfiles" << exec;
00387 if (!suggestedFileName.isEmpty()) {
00388 result << "--suggestedfilename";
00389 result << suggestedFileName;
00390 }
00391 result += _urls.toStringList();
00392 return result;
00393 }
00394
00395
00396 if (!mx1.hasUrls) {
00397 for (KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it)
00398 if (!(*it).isLocalFile() && !KProtocolInfo::isHelperProtocol(*it)) {
00399
00400 const QString kioexec = KStandardDirs::findExe("kioexec");
00401 Q_ASSERT(!kioexec.isEmpty());
00402 result << kioexec;
00403 if (tempFiles) {
00404 result << "--tempfiles";
00405 }
00406 if (!suggestedFileName.isEmpty()) {
00407 result << "--suggestedfilename";
00408 result << suggestedFileName;
00409 }
00410 result << exec;
00411 result += _urls.toStringList();
00412 return result;
00413 }
00414 }
00415
00416 if (appHasTempFileOption) {
00417 exec += " --tempfile";
00418 }
00419
00420
00421
00422
00423 if (!mx1.hasSpec) {
00424 exec += " %f";
00425 mx2.ignFile = true;
00426 }
00427
00428 mx2.expandMacrosShellQuote(exec);
00429
00430
00431
00432
00433
00434
00435
00436
00437
00438
00439
00440
00441
00442
00443
00444
00445
00446
00447 if (_service.terminal()) {
00448 KConfigGroup cg(KGlobal::config(), "General");
00449 QString terminal = cg.readPathEntry("TerminalApplication", "konsole");
00450 if (terminal == "konsole") {
00451 if (!_service.path().isEmpty()) {
00452 terminal += " --workdir " + KShell::quoteArg(_service.path());
00453 }
00454 terminal += " -caption=%c %i %m";
00455 }
00456 terminal += ' ';
00457 terminal += _service.terminalOptions();
00458 if (!mx1.expandMacrosShellQuote(terminal)) {
00459 kWarning() << "KRun: syntax error in command" << terminal << ", service" << _service.name();
00460 return QStringList();
00461 }
00462 mx2.expandMacrosShellQuote(terminal);
00463 result = KShell::splitArgs(terminal);
00464 result << "-e";
00465 }
00466
00467 KShell::Errors err;
00468 QStringList execlist = KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
00469 if (err == KShell::NoError && !execlist.isEmpty()) {
00470
00471
00472 const QString exePath = KStandardDirs::findExe(execlist[0]);
00473 if (!exePath.isEmpty()) {
00474 execlist[0] = exePath;
00475 }
00476 }
00477 if (_service.substituteUid()) {
00478 if (_service.terminal()) {
00479 result << "su";
00480 }
00481 else {
00482 result << KStandardDirs::findExe("kdesu") << "-u";
00483 }
00484
00485 result << _service.username() << "-c";
00486 if (err == KShell::FoundMeta) {
00487 exec = "/bin/sh -c " + KShell::quoteArg(exec);
00488 }
00489 else {
00490 exec = KShell::joinArgs(execlist);
00491 }
00492 result << exec;
00493 }
00494 else {
00495 if (err == KShell::FoundMeta) {
00496 result << "/bin/sh" << "-c" << exec;
00497 }
00498 else {
00499 result += execlist;
00500 }
00501 }
00502
00503 return result;
00504 }
00505
00506
00507 QString KRun::binaryName(const QString & execLine, bool removePath)
00508 {
00509
00510 const QStringList args = KShell::splitArgs(execLine);
00511 for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
00512 if (!(*it).contains('=')) {
00513
00514 return removePath ? (*it).mid((*it).lastIndexOf('/') + 1) : *it;
00515 }
00516 return QString();
00517 }
00518
00519 static bool runCommandInternal(KProcess* proc, const KService* service, const QString& executable,
00520 const QString &userVisibleName, const QString & iconName, QWidget* window,
00521 const QByteArray& asn)
00522 {
00523 if (window != NULL) {
00524 window = window->topLevelWidget();
00525 }
00526 if (service && !service->entryPath().isEmpty()
00527 && !KDesktopFile::isAuthorizedDesktopFile(service->entryPath()))
00528 {
00529 kWarning() << "No authorization to execute " << service->entryPath();
00530 KMessageBox::sorry(window, i18n("You are not authorized to execute this file."));
00531 delete proc;
00532 return false;
00533 }
00534
00535 QString bin = KRun::binaryName(executable, true);
00536 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00537 bool silent;
00538 QByteArray wmclass;
00539 KStartupInfoId id;
00540 bool startup_notify = (asn != "0" && KRun::checkStartupNotify(QString() , service, &silent, &wmclass));
00541 if (startup_notify) {
00542 id.initId(asn);
00543 id.setupStartupEnv();
00544 KStartupInfoData data;
00545 data.setHostname();
00546 data.setBin(bin);
00547 if (!userVisibleName.isEmpty()) {
00548 data.setName(userVisibleName);
00549 }
00550 else if (service && !service->name().isEmpty()) {
00551 data.setName(service->name());
00552 }
00553 data.setDescription(i18n("Launching %1" , data.name()));
00554 if (!iconName.isEmpty()) {
00555 data.setIcon(iconName);
00556 }
00557 else if (service && !service->icon().isEmpty()) {
00558 data.setIcon(service->icon());
00559 }
00560 if (!wmclass.isEmpty()) {
00561 data.setWMClass(wmclass);
00562 }
00563 if (silent) {
00564 data.setSilent(KStartupInfoData::Yes);
00565 }
00566 data.setDesktop(KWindowSystem::currentDesktop());
00567 if (window) {
00568 data.setLaunchedBy(window->winId());
00569 }
00570 KStartupInfo::sendStartup(id, data);
00571 }
00572 int pid = KProcessRunner::run(proc, executable, id);
00573 if (startup_notify && pid) {
00574 KStartupInfoData data;
00575 data.addPid(pid);
00576 KStartupInfo::sendChange(id, data);
00577 KStartupInfo::resetStartupEnv();
00578 }
00579 return pid != 0;
00580 #else
00581 Q_UNUSED(userVisibleName);
00582 Q_UNUSED(iconName);
00583 return KProcessRunner::run(proc, bin) != 0;
00584 #endif
00585 }
00586
00587
00588 bool KRun::checkStartupNotify(const QString& , const KService* service, bool* silent_arg, QByteArray* wmclass_arg)
00589 {
00590 bool silent = false;
00591 QByteArray wmclass;
00592 if (service && service->property("StartupNotify").isValid()) {
00593 silent = !service->property("StartupNotify").toBool();
00594 wmclass = service->property("StartupWMClass").toString().toLatin1();
00595 }
00596 else if (service && service->property("X-KDE-StartupNotify").isValid()) {
00597 silent = !service->property("X-KDE-StartupNotify").toBool();
00598 wmclass = service->property("X-KDE-WMClass").toString().toLatin1();
00599 }
00600 else {
00601 if (service) {
00602 if (service->isApplication()) {
00603 wmclass = "0";
00604 }
00605 else {
00606 return false;
00607 }
00608 }
00609 else {
00610 #if 0
00611
00612
00613
00614 wmclass = "0";
00615 silent = true;
00616 #else // That unfortunately doesn't work, when the launched non-compliant application
00617
00618 return false;
00619 #endif
00620 }
00621 }
00622 if (silent_arg != NULL) {
00623 *silent_arg = silent;
00624 }
00625 if (wmclass_arg != NULL) {
00626 *wmclass_arg = wmclass;
00627 }
00628 return true;
00629 }
00630
00631 static bool runTempService(const KService& _service, const KUrl::List& _urls, QWidget* window,
00632 bool tempFiles, const QString& suggestedFileName, const QByteArray& asn)
00633 {
00634 if (!_urls.isEmpty()) {
00635 kDebug(7010) << "runTempService: first url " << _urls.first().url();
00636 }
00637
00638 QStringList args;
00639 if ((_urls.count() > 1) && !_service.allowMultipleFiles()) {
00640
00641
00642
00643
00644
00645 KUrl::List::ConstIterator it = _urls.begin();
00646 while (++it != _urls.end()) {
00647 KUrl::List singleUrl;
00648 singleUrl.append(*it);
00649 runTempService(_service, singleUrl, window, tempFiles, suggestedFileName, QByteArray());
00650 }
00651 KUrl::List singleUrl;
00652 singleUrl.append(_urls.first());
00653 args = KRun::processDesktopExec(_service, singleUrl, tempFiles, suggestedFileName);
00654 }
00655 else {
00656 args = KRun::processDesktopExec(_service, _urls, tempFiles, suggestedFileName);
00657 }
00658 if (args.isEmpty()) {
00659 KMessageBox::sorry(window, i18n("Error processing Exec field in %1", _service.entryPath()));
00660 return false;
00661 }
00662 kDebug(7010) << "runTempService: KProcess args=" << args;
00663
00664 KProcess * proc = new KProcess;
00665 *proc << args;
00666
00667 if (!_service.path().isEmpty()) {
00668 proc->setWorkingDirectory(_service.path());
00669 }
00670
00671 return runCommandInternal(proc, &_service, KRun::binaryName(_service.exec(), false),
00672 _service.name(), _service.icon(), window, asn);
00673 }
00674
00675
00676 static KUrl::List resolveURLs(const KUrl::List& _urls, const KService& _service)
00677 {
00678
00679
00680 QStringList supportedProtocols = _service.property("X-KDE-Protocols").toStringList();
00681 KRunMX1 mx1(_service);
00682 QString exec = _service.exec();
00683 if (mx1.expandMacrosShellQuote(exec) && !mx1.hasUrls) {
00684 Q_ASSERT(supportedProtocols.isEmpty());
00685 }
00686 else {
00687 if (supportedProtocols.isEmpty()) {
00688
00689 QStringList categories = _service.property("Categories").toStringList();
00690 if (categories.contains("KDE")) {
00691 supportedProtocols.append("KIO");
00692 }
00693 else {
00694 supportedProtocols.append("http");
00695 supportedProtocols.append("ftp");
00696 }
00697 }
00698 }
00699 kDebug(7010) << "supportedProtocols:" << supportedProtocols;
00700
00701 KUrl::List urls(_urls);
00702 if (!supportedProtocols.contains("KIO")) {
00703 for (KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it) {
00704 const KUrl url = *it;
00705 bool supported = url.isLocalFile() || supportedProtocols.contains(url.protocol().toLower());
00706 kDebug(7010) << "Looking at url=" << url << " supported=" << supported;
00707 if (!supported && KProtocolInfo::protocolClass(url.protocol()) == ":local") {
00708
00709 KUrl localURL = KIO::NetAccess::mostLocalUrl(url, 0);
00710 if (localURL != url) {
00711 *it = localURL;
00712 kDebug(7010) << "Changed to " << localURL;
00713 }
00714 }
00715 }
00716 }
00717 return urls;
00718 }
00719
00720
00721
00722 class SecureMessageDialog : public KDialog
00723 {
00724 public:
00725 SecureMessageDialog(QWidget *parent) : KDialog(parent), m_textEdit(0)
00726 {
00727 }
00728
00729 void setTextEdit(QPlainTextEdit *textEdit)
00730 {
00731 m_textEdit = textEdit;
00732 }
00733
00734 protected:
00735 virtual void showEvent(QShowEvent* e)
00736 {
00737
00738
00739 KDialog::showEvent(e);
00740
00741 if(!m_textEdit)
00742 return;
00743
00744 QSize fudge(20, 24);
00745
00746
00747
00748 QRect curRect(m_textEdit->rect());
00749 QFontMetrics metrics(fontMetrics());
00750 curRect.setHeight(5 * metrics.lineSpacing());
00751 curRect.setWidth(qMax(curRect.width(), 300));
00752
00753 QString text(m_textEdit->toPlainText());
00754 curRect = metrics.boundingRect(curRect, Qt::TextWordWrap | Qt::TextSingleLine, text);
00755
00756
00757
00758 m_textEdit->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00759 if(curRect.height() < m_textEdit->height()) {
00760 m_textEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
00761 m_textEdit->setMaximumHeight(curRect.height() + fudge.height());
00762 }
00763
00764 m_textEdit->setMinimumSize(curRect.size() + fudge);
00765 m_textEdit->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
00766 updateGeometry();
00767 }
00768
00769 private:
00770 QPlainTextEdit *m_textEdit;
00771 };
00772
00773
00774
00775
00776 static bool makeFileExecutable(const QString &fileName)
00777 {
00778
00779
00780
00781 QFile desktopFile(fileName);
00782 if (!desktopFile.open(QFile::ReadOnly)) {
00783 kError(7010) << "Error opening service" << fileName << desktopFile.errorString();
00784 return false;
00785 }
00786
00787 QByteArray header = desktopFile.peek(2);
00788 if (header.size() == 0) {
00789 kError(7010) << "Error inspecting service" << fileName << desktopFile.errorString();
00790 return false;
00791 }
00792
00793 if (header != "#!") {
00794
00795 KSaveFile saveFile;
00796 saveFile.setFileName(fileName);
00797 if (!saveFile.open()) {
00798 kError(7010) << "Unable to open replacement file for" << fileName << saveFile.errorString();
00799 return false;
00800 }
00801
00802 QByteArray shebang("#!/usr/bin/env xdg-open\n");
00803 if (saveFile.write(shebang) != shebang.size()) {
00804 kError(7010) << "Error occurred adding header for" << fileName << saveFile.errorString();
00805 saveFile.abort();
00806 return false;
00807 }
00808
00809
00810 QByteArray desktopData(desktopFile.readAll());
00811 if (desktopData.isEmpty()) {
00812 kError(7010) << "Unable to read service" << fileName << desktopFile.errorString();
00813 saveFile.abort();
00814 return false;
00815 }
00816
00817 if (saveFile.write(desktopData) != desktopData.size()) {
00818 kError(7010) << "Error copying service" << fileName << saveFile.errorString();
00819 saveFile.abort();
00820 return false;
00821 }
00822
00823 desktopFile.close();
00824 if (!saveFile.finalize()) {
00825 kError(7010) << "Error committing changes to service" << fileName << saveFile.errorString();
00826 return false;
00827 }
00828
00829 if (!desktopFile.open(QFile::ReadOnly)) {
00830 kError(7010) << "Error re-opening service" << fileName << desktopFile.errorString();
00831 return false;
00832 }
00833 }
00834
00835
00836
00837 if (!desktopFile.setPermissions(QFile::ExeUser | desktopFile.permissions())) {
00838 kError(7010) << "Unable to change permissions for" << fileName << desktopFile.errorString();
00839 return false;
00840 }
00841
00842
00843 return true;
00844 }
00845
00846
00847
00848
00849 static bool makeServiceExecutable(const KService& service, QWidget* window)
00850 {
00851 if (!KAuthorized::authorize("run_desktop_files")) {
00852 kWarning() << "No authorization to execute " << service.entryPath();
00853 KMessageBox::sorry(window, i18n("You are not authorized to execute this service."));
00854 return false;
00855 }
00856
00857 KGuiItem continueItem = KStandardGuiItem::cont();
00858
00859 SecureMessageDialog *baseDialog = new SecureMessageDialog(window);
00860
00861 baseDialog->setButtons(KDialog::Ok | KDialog::Cancel);
00862 baseDialog->setButtonGuiItem(KDialog::Ok, continueItem);
00863 baseDialog->setDefaultButton(KDialog::Cancel);
00864 baseDialog->setButtonFocus(KDialog::Cancel);
00865 baseDialog->setCaption(i18nc("Warning about executing unknown .desktop file", "Warning"));
00866
00867
00868
00869 QWidget *baseWidget = new QWidget(baseDialog);
00870 QHBoxLayout *mainLayout = new QHBoxLayout(baseWidget);
00871
00872 QLabel *iconLabel = new QLabel(baseWidget);
00873 QPixmap warningIcon(KIconLoader::global()->loadIcon("dialog-warning", KIconLoader::NoGroup, KIconLoader::SizeHuge));
00874 mainLayout->addWidget(iconLabel);
00875 iconLabel->setPixmap(warningIcon);
00876
00877 QVBoxLayout *contentLayout = new QVBoxLayout;
00878 QString warningMessage = i18nc("program name follows in a line edit below",
00879 "This will start the program:");
00880
00881 QLabel *message = new QLabel(warningMessage, baseWidget);
00882 contentLayout->addWidget(message);
00883
00884
00885
00886 QString program = KStandardDirs::realFilePath(service.exec());
00887
00888 QPlainTextEdit *textEdit = new QPlainTextEdit(baseWidget);
00889 textEdit->setPlainText(program);
00890 textEdit->setReadOnly(true);
00891 contentLayout->addWidget(textEdit);
00892
00893 QLabel *footerLabel = new QLabel(i18n("If you do not trust this program, click Cancel"));
00894 contentLayout->addWidget(footerLabel);
00895 contentLayout->addStretch(0);
00896
00897 mainLayout->addLayout(contentLayout);
00898
00899 baseDialog->setMainWidget(baseWidget);
00900 baseDialog->setTextEdit(textEdit);
00901
00902
00903
00904 QSize screenSize = QApplication::desktop()->screen()->size();
00905 baseDialog->resize(screenSize.width() / 4, 50);
00906 baseDialog->setMaximumHeight(screenSize.height() / 3);
00907 baseDialog->setMaximumWidth(screenSize.width() / 10 * 8);
00908
00909 int result = baseDialog->exec();
00910 if (result != KDialog::Accepted) {
00911 return false;
00912 }
00913
00914
00915
00916
00917
00918
00919 if (!::makeFileExecutable(service.entryPath())) {
00920 QString serviceName = service.name();
00921 if(serviceName.isEmpty())
00922 serviceName = service.genericName();
00923
00924 KMessageBox::sorry(
00925 window,
00926 i18n("Unable to make the service %1 executable, aborting execution", serviceName)
00927 );
00928
00929 return false;
00930 }
00931
00932 return true;
00933 }
00934
00935 bool KRun::run(const KService& _service, const KUrl::List& _urls, QWidget* window,
00936 bool tempFiles, const QString& suggestedFileName, const QByteArray& asn)
00937 {
00938 if (!_service.entryPath().isEmpty() &&
00939 !KDesktopFile::isAuthorizedDesktopFile(_service.entryPath()) &&
00940 !::makeServiceExecutable(_service, window))
00941 {
00942 return false;
00943 }
00944
00945 if (!tempFiles) {
00946
00947 KUrl::List::ConstIterator it = _urls.begin();
00948 for (; it != _urls.end(); ++it) {
00949
00950 KRecentDocument::add(*it, _service.desktopEntryName());
00951 }
00952 }
00953
00954 if (tempFiles || _service.entryPath().isEmpty() || !suggestedFileName.isEmpty()) {
00955 return runTempService(_service, _urls, window, tempFiles, suggestedFileName, asn);
00956 }
00957
00958 kDebug(7010) << "KRun::run " << _service.entryPath();
00959
00960 if (!_urls.isEmpty()) {
00961 kDebug(7010) << "First url " << _urls.first().url();
00962 }
00963
00964
00965 const KUrl::List urls = resolveURLs(_urls, _service);
00966
00967 QString error;
00968 int pid = 0;
00969
00970 QByteArray myasn = asn;
00971
00972 if (window != NULL) {
00973 if (myasn.isEmpty()) {
00974 myasn = KStartupInfo::createNewStartupId();
00975 }
00976 if (myasn != "0") {
00977 KStartupInfoId id;
00978 id.initId(myasn);
00979 KStartupInfoData data;
00980 data.setLaunchedBy(window->winId());
00981 KStartupInfo::sendChange(id, data);
00982 }
00983 }
00984
00985 int i = KToolInvocation::startServiceByDesktopPath(
00986 _service.entryPath(), urls.toStringList(), &error, 0L, &pid, myasn
00987 );
00988
00989 if (i != 0) {
00990 kDebug(7010) << error;
00991 KMessageBox::sorry(window, error);
00992 return false;
00993 }
00994
00995 kDebug(7010) << "startServiceByDesktopPath worked fine";
00996 return true;
00997 }
00998
00999
01000 bool KRun::run(const QString& _exec, const KUrl::List& _urls, QWidget* window, const QString& _name,
01001 const QString& _icon, const QByteArray& asn)
01002 {
01003 KService::Ptr service(new KService(_name, _exec, _icon));
01004
01005 return run(*service, _urls, window, false, QString(), asn);
01006 }
01007
01008 bool KRun::runCommand(const QString &cmd, QWidget* window)
01009 {
01010 if (cmd.isEmpty()) {
01011 kWarning() << "Command was empty, nothing to run";
01012 return false;
01013 }
01014 const QString bin = KShell::splitArgs(cmd).first();
01015 return KRun::runCommand(cmd, bin, bin , window, QByteArray());
01016 }
01017
01018 bool KRun::runCommand(const QString& cmd, const QString &execName, const QString & iconName, QWidget* window, const QByteArray& asn)
01019 {
01020 kDebug(7010) << "runCommand " << cmd << "," << execName;
01021 KProcess * proc = new KProcess;
01022 proc->setShellCommand(cmd);
01023 QString bin = binaryName(execName, true);
01024 KService::Ptr service = KService::serviceByDesktopName(bin);
01025 return runCommandInternal(proc, service.data(),
01026 execName ,
01027 execName ,
01028 iconName, window, asn);
01029 }
01030
01031 KRun::KRun(const KUrl& url, QWidget* window, mode_t mode, bool isLocalFile,
01032 bool showProgressInfo, const QByteArray& asn)
01033 : d(new KRunPrivate(this))
01034 {
01035 d->m_timer.setObjectName("KRun::timer");
01036 d->m_timer.setSingleShot(true);
01037 d->init(url, window, mode, isLocalFile, showProgressInfo, asn);
01038 }
01039
01040 void KRun::KRunPrivate::init(const KUrl& url, QWidget* window, mode_t mode, bool isLocalFile,
01041 bool showProgressInfo, const QByteArray& asn)
01042 {
01043 m_bFault = false;
01044 m_bAutoDelete = true;
01045 m_bProgressInfo = showProgressInfo;
01046 m_bFinished = false;
01047 m_job = 0L;
01048 m_strURL = url;
01049 m_bScanFile = false;
01050 m_bIsDirectory = false;
01051 m_bIsLocalFile = isLocalFile;
01052 m_mode = mode;
01053 m_runExecutables = true;
01054 m_window = window;
01055 m_asn = asn;
01056 q->setEnableExternalBrowser(true);
01057
01058
01059
01060
01061 m_bInit = true;
01062 q->connect(&m_timer, SIGNAL(timeout()), q, SLOT(slotTimeout()));
01063 startTimer();
01064
01065
01066 KGlobal::ref();
01067 }
01068
01069 void KRun::init()
01070 {
01071 kDebug(7010) << "INIT called";
01072 if (!d->m_strURL.isValid()) {
01073
01074 d->m_showingDialog = true;
01075 KMessageBoxWrapper::error(d->m_window, i18n("Malformed URL\n%1", d->m_strURL.url()));
01076 d->m_showingDialog = false;
01077 d->m_bFault = true;
01078 d->m_bFinished = true;
01079 d->startTimer();
01080 return;
01081 }
01082 if (!KAuthorized::authorizeUrlAction("open", KUrl(), d->m_strURL)) {
01083 QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->m_strURL.prettyUrl());
01084 d->m_showingDialog = true;
01085 KMessageBoxWrapper::error(d->m_window, msg);
01086 d->m_showingDialog = false;
01087 d->m_bFault = true;
01088 d->m_bFinished = true;
01089 d->startTimer();
01090 return;
01091 }
01092
01093 if (!d->m_bIsLocalFile && d->m_strURL.isLocalFile()) {
01094 d->m_bIsLocalFile = true;
01095 }
01096
01097 QString exec;
01098 if (d->m_strURL.protocol().startsWith("http")) {
01099 exec = d->m_externalBrowser;
01100 }
01101
01102 if (d->m_bIsLocalFile) {
01103 if (d->m_mode == 0) {
01104 KDE_struct_stat buff;
01105 if (KDE::stat(d->m_strURL.path(), &buff) == -1) {
01106 d->m_showingDialog = true;
01107 KMessageBoxWrapper::error(d->m_window,
01108 i18n("<qt>Unable to run the command specified. "
01109 "The file or folder <b>%1</b> does not exist.</qt>" ,
01110 Qt::escape(d->m_strURL.prettyUrl())));
01111 d->m_showingDialog = false;
01112 d->m_bFault = true;
01113 d->m_bFinished = true;
01114 d->startTimer();
01115 return;
01116 }
01117 d->m_mode = buff.st_mode;
01118 }
01119
01120 KMimeType::Ptr mime = KMimeType::findByUrl(d->m_strURL, d->m_mode, d->m_bIsLocalFile);
01121 assert(mime);
01122 kDebug(7010) << "MIME TYPE is " << mime->name();
01123 mimeTypeDetermined(mime->name());
01124 return;
01125 }
01126 else if (!exec.isEmpty() || KProtocolInfo::isHelperProtocol(d->m_strURL)) {
01127 kDebug(7010) << "Helper protocol";
01128
01129 bool ok = false;
01130 KUrl::List urls;
01131 urls.append(d->m_strURL);
01132 if (exec.isEmpty()) {
01133 exec = KProtocolInfo::exec(d->m_strURL.protocol());
01134 if (exec.isEmpty()) {
01135 mimeTypeDetermined(KProtocolManager::defaultMimetype(d->m_strURL));
01136 return;
01137 }
01138 run(exec, urls, d->m_window, false, QString(), d->m_asn);
01139 ok = true;
01140 }
01141 else if (exec.startsWith('!')) {
01142 exec = exec.mid(1);
01143 exec += " %u";
01144 run(exec, urls, d->m_window, false, QString(), d->m_asn);
01145 ok = true;
01146 }
01147 else {
01148 KService::Ptr service = KService::serviceByStorageId(exec);
01149 if (service) {
01150 run(*service, urls, d->m_window, false, QString(), d->m_asn);
01151 ok = true;
01152 }
01153 }
01154
01155 if (ok) {
01156 d->m_bFinished = true;
01157
01158 d->startTimer();
01159 return;
01160 }
01161 }
01162
01163
01164 if (S_ISDIR(d->m_mode)) {
01165 mimeTypeDetermined("inode/directory");
01166 return;
01167 }
01168
01169
01170
01171 if (!KProtocolManager::supportsListing(d->m_strURL)) {
01172
01173
01174 scanFile();
01175 return;
01176 }
01177
01178 kDebug(7010) << "Testing directory (stating)";
01179
01180
01181 KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
01182 KIO::StatJob *job = KIO::stat(d->m_strURL, KIO::StatJob::SourceSide, 0 , flags);
01183 job->ui()->setWindow(d->m_window);
01184 connect(job, SIGNAL(result(KJob *)),
01185 this, SLOT(slotStatResult(KJob *)));
01186 d->m_job = job;
01187 kDebug(7010) << " Job " << job << " is about stating " << d->m_strURL.url();
01188 }
01189
01190 KRun::~KRun()
01191 {
01192
01193 d->m_timer.stop();
01194 killJob();
01195 KGlobal::deref();
01196
01197 delete d;
01198 }
01199
01200 void KRun::scanFile()
01201 {
01202 kDebug(7010) << d->m_strURL;
01203
01204
01205 if (d->m_strURL.query().isEmpty()) {
01206 KMimeType::Ptr mime = KMimeType::findByUrl(d->m_strURL);
01207 assert(mime);
01208 if (mime->name() != "application/octet-stream" || d->m_bIsLocalFile) {
01209 kDebug(7010) << "Scanfile: MIME TYPE is " << mime->name();
01210 mimeTypeDetermined(mime->name());
01211 return;
01212 }
01213 }
01214
01215
01216
01217
01218
01219 if (!KProtocolManager::supportsReading(d->m_strURL)) {
01220 kError(7010) << "#### NO SUPPORT FOR READING!";
01221 d->m_bFault = true;
01222 d->m_bFinished = true;
01223 d->startTimer();
01224 return;
01225 }
01226 kDebug(7010) << this << " Scanning file " << d->m_strURL.url();
01227
01228 KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
01229 KIO::TransferJob *job = KIO::get(d->m_strURL, KIO::NoReload , flags);
01230 job->ui()->setWindow(d->m_window);
01231 connect(job, SIGNAL(result(KJob *)),
01232 this, SLOT(slotScanFinished(KJob *)));
01233 connect(job, SIGNAL(mimetype(KIO::Job *, const QString &)),
01234 this, SLOT(slotScanMimeType(KIO::Job *, const QString &)));
01235 d->m_job = job;
01236 kDebug(7010) << " Job " << job << " is about getting from " << d->m_strURL.url();
01237 }
01238
01239 void KRun::slotTimeout()
01240 {
01241 kDebug(7010) << this << " slotTimeout called";
01242 if (d->m_bInit) {
01243 d->m_bInit = false;
01244 init();
01245 return;
01246 }
01247
01248 if (d->m_bFault) {
01249 emit error();
01250 }
01251 if (d->m_bFinished) {
01252 emit finished();
01253 }
01254 else {
01255 if (d->m_bScanFile) {
01256 d->m_bScanFile = false;
01257 scanFile();
01258 return;
01259 }
01260 else if (d->m_bIsDirectory) {
01261 d->m_bIsDirectory = false;
01262 mimeTypeDetermined("inode/directory");
01263 return;
01264 }
01265 }
01266
01267 if (d->m_bAutoDelete) {
01268 deleteLater();
01269 return;
01270 }
01271 }
01272
01273 void KRun::slotStatResult(KJob * job)
01274 {
01275 d->m_job = 0L;
01276 if (job->error()) {
01277 d->m_showingDialog = true;
01278 kError(7010) << this << "ERROR" << job->error() << ' ' << job->errorString();
01279 job->uiDelegate()->showErrorMessage();
01280
01281 d->m_showingDialog = false;
01282
01283 d->m_bFault = true;
01284 d->m_bFinished = true;
01285
01286
01287 d->startTimer();
01288
01289 }
01290 else {
01291
01292 kDebug(7010) << "Finished";
01293 if (!qobject_cast<KIO::StatJob*>(job)) {
01294 kFatal() << "job is a " << typeid(*job).name() << " should be a StatJob";
01295 }
01296
01297 const KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
01298 const mode_t mode = entry.numberValue(KIO::UDSEntry::UDS_FILE_TYPE);
01299 if (S_ISDIR(mode)) {
01300 d->m_bIsDirectory = true;
01301 }
01302 else {
01303 d->m_bScanFile = true;
01304 }
01305
01306 d->m_localPath = entry.stringValue(KIO::UDSEntry::UDS_LOCAL_PATH);
01307
01308
01309 const QString knownMimeType = entry.stringValue(KIO::UDSEntry::UDS_MIME_TYPE) ;
01310
01311 if (!knownMimeType.isEmpty()) {
01312 mimeTypeDetermined(knownMimeType);
01313 d->m_bFinished = true;
01314 }
01315
01316
01317 assert(d->m_bScanFile || d->m_bIsDirectory);
01318
01319
01320
01321
01322 d->startTimer();
01323 }
01324 }
01325
01326 void KRun::slotScanMimeType(KIO::Job *, const QString &mimetype)
01327 {
01328 if (mimetype.isEmpty()) {
01329 kWarning(7010) << "get() didn't emit a mimetype! Probably a kioslave bug, please check the implementation of" << url().protocol();
01330 }
01331 mimeTypeDetermined(mimetype);
01332 d->m_job = 0;
01333 }
01334
01335 void KRun::slotScanFinished(KJob *job)
01336 {
01337 d->m_job = 0;
01338 if (job->error()) {
01339 d->m_showingDialog = true;
01340 kError(7010) << this << "ERROR (stat):" << job->error() << ' ' << job->errorString();
01341 job->uiDelegate()->showErrorMessage();
01342
01343 d->m_showingDialog = false;
01344
01345 d->m_bFault = true;
01346 d->m_bFinished = true;
01347
01348
01349 d->startTimer();
01350 }
01351 }
01352
01353 void KRun::mimeTypeDetermined(const QString& mimeType)
01354 {
01355
01356
01357 Q_ASSERT(!d->m_showingDialog);
01358 d->m_showingDialog = true;
01359
01360 foundMimeType(mimeType);
01361
01362 d->m_showingDialog = false;
01363 }
01364
01365 void KRun::foundMimeType(const QString& type)
01366 {
01367 kDebug(7010) << "Resulting mime type is " << type;
01368
01369
01370
01371
01372
01373
01374
01375
01376
01377
01378
01379
01380
01381
01382
01383
01384
01385
01386
01387
01388
01389
01390
01391
01392
01393
01394
01395
01396
01397
01398
01399
01400
01401
01402
01403
01404
01405
01406
01407
01408
01409
01410
01411
01412
01413
01414
01415
01416
01417
01418
01419
01420
01421
01422
01423
01424
01425
01426
01427 KIO::TransferJob *job = qobject_cast<KIO::TransferJob *>(d->m_job);
01428 if (job) {
01429 job->putOnHold();
01430 KIO::Scheduler::publishSlaveOnHold();
01431 d->m_job = 0;
01432 }
01433
01434 Q_ASSERT(!d->m_bFinished);
01435
01436 KMimeType::Ptr mime = KMimeType::mimeType(type, KMimeType::ResolveAliases);
01437 if (!mime) {
01438 kWarning(7010) << "Unknown mimetype " << type;
01439 }
01440
01441
01442 if (!d->m_preferredService.isEmpty()) {
01443 kDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService;
01444 KService::Ptr serv = KService::serviceByDesktopName(d->m_preferredService);
01445 if (serv && serv->hasMimeType(mime.data())) {
01446 KUrl::List lst;
01447 lst.append(d->m_strURL);
01448 d->m_bFinished = KRun::run(*serv, lst, d->m_window, false, QString(), d->m_asn);
01453 }
01454 }
01455
01456
01457 if (mime && mime->is("application/x-desktop") && !d->m_localPath.isEmpty()) {
01458 d->m_strURL = KUrl();
01459 d->m_strURL.setPath(d->m_localPath);
01460 }
01461
01462 if (!d->m_bFinished && KRun::runUrl(d->m_strURL, type, d->m_window, false , d->m_runExecutables, d->m_suggestedFileName, d->m_asn)) {
01463 d->m_bFinished = true;
01464 }
01465 else {
01466 d->m_bFinished = true;
01467 d->m_bFault = true;
01468 }
01469
01470 d->startTimer();
01471 }
01472
01473 void KRun::killJob()
01474 {
01475 if (d->m_job) {
01476 kDebug(7010) << this << "m_job=" << d->m_job;
01477 d->m_job->kill();
01478 d->m_job = 0L;
01479 }
01480 }
01481
01482 void KRun::abort()
01483 {
01484 kDebug(7010) << this << "m_showingDialog=" << d->m_showingDialog;
01485 killJob();
01486
01487
01488 if (d->m_showingDialog) {
01489 return;
01490 }
01491 d->m_bFault = true;
01492 d->m_bFinished = true;
01493 d->m_bInit = false;
01494 d->m_bScanFile = false;
01495
01496
01497 d->startTimer();
01498 }
01499
01500 bool KRun::hasError() const
01501 {
01502 return d->m_bFault;
01503 }
01504
01505 bool KRun::hasFinished() const
01506 {
01507 return d->m_bFinished;
01508 }
01509
01510 bool KRun::autoDelete() const
01511 {
01512 return d->m_bAutoDelete;
01513 }
01514
01515 void KRun::setAutoDelete(bool b)
01516 {
01517 d->m_bAutoDelete = b;
01518 }
01519
01520 void KRun::setEnableExternalBrowser(bool b)
01521 {
01522 if (b) {
01523 d->m_externalBrowser = KConfigGroup(KGlobal::config(), "General").readEntry("BrowserApplication");
01524 }
01525 else {
01526 d->m_externalBrowser.clear();
01527 }
01528 }
01529
01530 void KRun::setPreferredService(const QString& desktopEntryName)
01531 {
01532 d->m_preferredService = desktopEntryName;
01533 }
01534
01535 void KRun::setRunExecutables(bool b)
01536 {
01537 d->m_runExecutables = b;
01538 }
01539
01540 void KRun::setSuggestedFileName(const QString& fileName)
01541 {
01542 d->m_suggestedFileName = fileName;
01543 }
01544
01545 QString KRun::suggestedFileName() const
01546 {
01547 return d->m_suggestedFileName;
01548 }
01549
01550 bool KRun::isExecutable(const QString& serviceType)
01551 {
01552 return (serviceType == "application/x-desktop" ||
01553 serviceType == "application/x-executable" ||
01554 serviceType == "application/x-ms-dos-executable" ||
01555 serviceType == "application/x-shellscript");
01556 }
01557
01558 void KRun::setUrl(const KUrl &url)
01559 {
01560 d->m_strURL = url;
01561 }
01562
01563 KUrl KRun::url() const
01564 {
01565 return d->m_strURL;
01566 }
01567
01568 void KRun::setError(bool error)
01569 {
01570 d->m_bFault = error;
01571 }
01572
01573 void KRun::setProgressInfo(bool progressInfo)
01574 {
01575 d->m_bProgressInfo = progressInfo;
01576 }
01577
01578 bool KRun::progressInfo() const
01579 {
01580 return d->m_bProgressInfo;
01581 }
01582
01583 void KRun::setFinished(bool finished)
01584 {
01585 d->m_bFinished = finished;
01586
01587 }
01588
01589 void KRun::setJob(KIO::Job *job)
01590 {
01591 d->m_job = job;
01592 }
01593
01594 KIO::Job* KRun::job()
01595 {
01596 return d->m_job;
01597 }
01598
01599 QTimer& KRun::timer()
01600 {
01601 return d->m_timer;
01602 }
01603
01604 void KRun::setDoScanFile(bool scanFile)
01605 {
01606 d->m_bScanFile = scanFile;
01607 }
01608
01609 bool KRun::doScanFile() const
01610 {
01611 return d->m_bScanFile;
01612 }
01613
01614 void KRun::setIsDirecory(bool isDirectory)
01615 {
01616 d->m_bIsDirectory = isDirectory;
01617 }
01618
01619 bool KRun::isDirectory() const
01620 {
01621 return d->m_bIsDirectory;
01622 }
01623
01624 void KRun::setInitializeNextAction(bool initialize)
01625 {
01626 d->m_bInit = initialize;
01627 }
01628
01629 bool KRun::initializeNextAction() const
01630 {
01631 return d->m_bInit;
01632 }
01633
01634 void KRun::setIsLocalFile(bool isLocalFile)
01635 {
01636 d->m_bIsLocalFile = isLocalFile;
01637 }
01638
01639 bool KRun::isLocalFile() const
01640 {
01641 return d->m_bIsLocalFile;
01642 }
01643
01644 void KRun::setMode(mode_t mode)
01645 {
01646 d->m_mode = mode;
01647 }
01648
01649 mode_t KRun::mode() const
01650 {
01651 return d->m_mode;
01652 }
01653
01654
01655
01656 #ifndef Q_WS_X11
01657 int KProcessRunner::run(KProcess * p, const QString & executable)
01658 {
01659 return (new KProcessRunner(p, executable))->pid();
01660 }
01661 #else
01662 int KProcessRunner::run(KProcess * p, const QString & executable, const KStartupInfoId& id)
01663 {
01664 return (new KProcessRunner(p, executable, id))->pid();
01665 }
01666 #endif
01667
01668 #ifndef Q_WS_X11
01669 KProcessRunner::KProcessRunner(KProcess * p, const QString & executable)
01670 #else
01671 KProcessRunner::KProcessRunner(KProcess * p, const QString & executable, const KStartupInfoId& _id) :
01672 id(_id)
01673 #endif
01674 {
01675 m_pid = 0;
01676 process = p;
01677 m_executable = executable;
01678 connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
01679 this, SLOT(slotProcessExited(int, QProcess::ExitStatus)));
01680
01681 process->start();
01682 if (!process->waitForStarted()) {
01683
01684
01685
01686 slotProcessExited(255, process->exitStatus());
01687 }
01688 else {
01689 #ifdef Q_WS_X11
01690 m_pid = process->pid();
01691 #endif
01692 }
01693 }
01694
01695 KProcessRunner::~KProcessRunner()
01696 {
01697 delete process;
01698 }
01699
01700 int KProcessRunner::pid() const
01701 {
01702 return m_pid;
01703 }
01704
01705 void KProcessRunner::terminateStartupNotification()
01706 {
01707 #ifdef Q_WS_X11
01708 if (!id.none()) {
01709 KStartupInfoData data;
01710 data.addPid(m_pid);
01711 data.setHostname();
01712 KStartupInfo::sendFinish(id, data);
01713 }
01714 #endif
01715
01716 }
01717
01718 void
01719 KProcessRunner::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
01720 {
01721 kDebug(7010) << m_executable << "exitCode=" << exitCode << "exitStatus=" << exitStatus;
01722 Q_UNUSED(exitStatus);
01723
01724 terminateStartupNotification();
01725 if (exitCode != 0 && !m_executable.isEmpty()) {
01726
01727
01728
01729
01730
01731
01732 if (!QFile(m_executable).exists() && KStandardDirs::findExe(m_executable).isEmpty()) {
01733 KGlobal::ref();
01734 KMessageBox::sorry(0L, i18n("Could not find the program '%1'", m_executable));
01735 KGlobal::deref();
01736 }
01737 else {
01738 kDebug() << process->readAllStandardError();
01739 }
01740 }
01741 deleteLater();
01742 }
01743
01744 #include "krun.moc"
01745 #include "krun_p.moc"