• Skip to content
  • Skip to link menu
KDE 4.1 API Reference
  • KDE API Reference
  • kdelibs
  • Sitemap
  • Contact Us
 

KIO

krun.cpp

Go to the documentation of this file.
00001 /* This file is part of the KDE libraries
00002     Copyright (C) 2000 Torben Weis <weis@kde.org>
00003     Copyright (C) 2006 David Faure <faure@kde.org>
00004 
00005     This library is free software; you can redistribute it and/or
00006     modify it under the terms of the GNU Library General Public
00007     License as published by the Free Software Foundation; either
00008     version 2 of the License, or (at your option) any later version.
00009 
00010     This library is distributed in the hope that it will be useful,
00011     but WITHOUT ANY WARRANTY; without even the implied warranty of
00012     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013     Library General Public License for more details.
00014 
00015     You should have received a copy of the GNU Library General Public License
00016     along with this library; see the file COPYING.LIB.  If not, write to
00017     the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00018     Boston, MA 02110-1301, USA.
00019 */
00020 
00021 #include "krun.h"
00022 #include "krun_p.h"
00023 
00024 #include <config.h>
00025 
00026 #include <assert.h>
00027 #include <stdlib.h>
00028 #include <string.h>
00029 #include <unistd.h>
00030 #include <typeinfo>
00031 #include <sys/stat.h>
00032 
00033 #include <QtGui/QWidget>
00034 
00035 #include "kmimetypetrader.h"
00036 #include "kmimetype.h"
00037 #include "kio/jobclasses.h" // for KIO::JobFlags
00038 #include "kio/job.h"
00039 #include "kio/jobuidelegate.h"
00040 #include "kio/global.h"
00041 #include "kio/scheduler.h"
00042 #include "kio/netaccess.h"
00043 #include "kfile/kopenwithdialog.h"
00044 #include "kfile/krecentdocument.h"
00045 #include "kdesktopfileactions.h"
00046 
00047 #include <kmessageboxwrapper.h>
00048 #include <kurl.h>
00049 #include <kglobal.h>
00050 #include <ktoolinvocation.h>
00051 #include <kauthorized.h>
00052 #include <kdebug.h>
00053 #include <klocale.h>
00054 #include <kprotocolmanager.h>
00055 #include <kstandarddirs.h>
00056 #include <kprocess.h>
00057 #include <QtCore/QFile>
00058 #include <QtCore/QFileInfo>
00059 #include <QtCore/QTextIStream>
00060 #include <QtCore/QDate>
00061 #include <QtCore/QRegExp>
00062 #include <kdesktopfile.h>
00063 #include <kmacroexpander.h>
00064 #include <kshell.h>
00065 #include <QTextDocument>
00066 #include <kde_file.h>
00067 #include <kconfiggroup.h>
00068 
00069 #ifdef Q_WS_X11
00070 #include <kwindowsystem.h>
00071 #endif
00072 
00073 KRun::KRunPrivate::KRunPrivate(KRun *parent)
00074   : q(parent),
00075     m_showingDialog(false)
00076 {
00077 }
00078 
00079 void KRun::KRunPrivate::startTimer()
00080 {
00081     m_timer.start(0);
00082 }
00083 
00084 // ---------------------------------------------------------------------------
00085 
00086 bool KRun::isExecutableFile( const KUrl& url, const QString &mimetype )
00087 {
00088   if ( !url.isLocalFile() )
00089      return false;
00090   QFileInfo file( url.path() );
00091   if ( file.isExecutable() ) {  // Got a prospective file to run
00092     KMimeType::Ptr mimeType = KMimeType::mimeType(mimetype, KMimeType::ResolveAliases);
00093     if ( mimeType && (mimeType->is("application/x-executable") || mimeType->is("application/x-executable-script")) )
00094       return true;
00095   }
00096   return false;
00097 }
00098 
00099 // This is called by foundMimeType, since it knows the mimetype of the URL
00100 bool KRun::runUrl( const KUrl& u, const QString& _mimetype, QWidget* window, bool tempFile, bool runExecutables, const QString& suggestedFileName, const QByteArray& asn )
00101 {
00102   bool noRun = false;
00103   bool noAuth = false;
00104   if ( _mimetype == "inode/directory-locked" )
00105   {
00106     KMessageBoxWrapper::error( window,
00107             i18n("<qt>Unable to enter <b>%1</b>.\nYou do not have access rights to this location.</qt>", Qt::escape(u.prettyUrl())) );
00108     return false;
00109   }
00110   else if ( _mimetype == "application/x-desktop" )
00111   {
00112     if ( u.isLocalFile() && runExecutables )
00113       return KDesktopFileActions::run( u, true );
00114   }
00115   else if ( isExecutableFile(u, _mimetype) )
00116   {
00117     if ( u.isLocalFile() && runExecutables)
00118     {
00119       if (KAuthorized::authorize("shell_access"))
00120       {
00121         return (KRun::runCommand(KShell::quoteArg(u.path()), QString(), QString(), window, asn)); // just execute the url as a command
00122         // ## TODO implement deleting the file if tempFile==true
00123       }
00124       else
00125       {
00126         noAuth = true;
00127       }
00128     }
00129     else if (_mimetype == "application/x-executable")
00130       noRun = true;
00131   }
00132   else if ( isExecutable(_mimetype) )
00133   {
00134     if (!runExecutables)
00135       noRun = true;
00136 
00137     if (!KAuthorized::authorize("shell_access"))
00138       noAuth = true;
00139   }
00140 
00141   if ( noRun )
00142   {
00143     KMessageBox::sorry( window,
00144         i18n("<qt>The file <b>%1</b> is an executable program. "
00145              "For safety it will not be started.</qt>", Qt::escape(u.prettyUrl())));
00146     return false;
00147   }
00148   if ( noAuth )
00149   {
00150     KMessageBoxWrapper::error( window,
00151         i18n("<qt>You do not have permission to run <b>%1</b>.</qt>", Qt::escape(u.prettyUrl())) );
00152     return false;
00153   }
00154 
00155   KUrl::List lst;
00156   lst.append( u );
00157 
00158   KService::Ptr offer = KMimeTypeTrader::self()->preferredService( _mimetype );
00159 
00160   if ( !offer )
00161   {
00162     // Open-with dialog
00163     // TODO : pass the mimetype as a parameter, to show it (comment field) in the dialog !
00164     // Hmm, in fact KOpenWithDialog::setServiceType already guesses the mimetype from the first URL of the list...
00165     return displayOpenWithDialog( lst, window, tempFile, suggestedFileName, asn );
00166   }
00167 
00168   return KRun::run( *offer, lst, window, tempFile, suggestedFileName, asn );
00169 }
00170 
00171 bool KRun::displayOpenWithDialog( const KUrl::List& lst, QWidget* window, bool tempFiles, 
00172                                   const QString& suggestedFileName, const QByteArray& asn )
00173 {
00174     if (!KAuthorized::authorizeKAction("openwith"))
00175     {
00176        KMessageBox::sorry(window, 
00177          i18n("You are not authorized to select an application to open this file."));
00178        return false;
00179     }
00180 
00181 #ifdef Q_WS_WIN
00182     KConfigGroup cfgGroup(KGlobal::config(), "KOpenWithDialog Settings");
00183     if (cfgGroup.readEntry("Native", true))
00184     {
00185       return KRun::KRunPrivate::displayNativeOpenWithDialog( lst, window, tempFiles,
00186                                                        suggestedFileName, asn );
00187     }
00188 #endif
00189     KOpenWithDialog l( lst, i18n("Open with:"), QString(), window );
00190     if ( l.exec() )
00191     {
00192       KService::Ptr service = l.service();
00193       if ( service )
00194         return KRun::run( *service, lst, window, tempFiles, suggestedFileName, asn );
00195 
00196       kDebug(7010) << "No service set, running " << l.text();
00197       return KRun::run( l.text(), lst, window, false, suggestedFileName, asn ); // TODO handle tempFiles
00198     }
00199     return false;
00200 }
00201 
00202 void KRun::shellQuote( QString &_str )
00203 {
00204     // Credits to Walter, says Bernd G. :)
00205     if (_str.isEmpty()) // Don't create an explicit empty parameter
00206         return;
00207     QChar q('\'');
00208     _str.replace(q, "'\\''").prepend(q).append(q);
00209 }
00210 
00211 
00212 class KRunMX1 : public KMacroExpanderBase {
00213 public:
00214     KRunMX1( const KService &_service ) :
00215         KMacroExpanderBase( '%' ), hasUrls( false ), hasSpec( false ), service( _service ) {}
00216     bool hasUrls:1, hasSpec:1;
00217 
00218 protected:
00219     virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
00220 
00221 private:
00222     const KService &service;
00223 };
00224 
00225 int
00226 KRunMX1::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00227 {
00228    uint option = str[pos + 1].unicode();
00229    switch( option ) {
00230    case 'c':
00231       ret << service.name().replace( '%', "%%" );
00232       break;
00233    case 'k':
00234       ret << service.entryPath().replace( '%', "%%" );
00235       break;
00236    case 'i':
00237       ret << "-icon" << service.icon().replace( '%', "%%" );
00238       break;
00239    case 'm':
00240 //       ret << "-miniicon" << service.icon().replace( '%', "%%" );
00241       kWarning() << "-miniicon isn't supported anymore (service"
00242                   << service.name() << ')';
00243       break;
00244    case 'u':
00245    case 'U':
00246       hasUrls = true;
00247       /* fallthrough */
00248    case 'f':
00249    case 'F':
00250    case 'n':
00251    case 'N':
00252    case 'd':
00253    case 'D':
00254    case 'v':
00255       hasSpec = true;
00256       /* fallthrough */
00257    default:
00258       return -2; // subst with same and skip
00259    }
00260    return 2;
00261 }
00262 
00263 class KRunMX2 : public KMacroExpanderBase {
00264 public:
00265     KRunMX2( const KUrl::List &_urls ) :
00266         KMacroExpanderBase( '%' ), ignFile( false ), urls( _urls ) {}
00267     bool ignFile:1;
00268 
00269 protected:
00270     virtual int expandEscapedMacro( const QString &str, int pos, QStringList &ret );
00271 
00272 private:
00273     void subst( int option, const KUrl &url, QStringList &ret );
00274 
00275     const KUrl::List &urls;
00276 };
00277 
00278 void
00279 KRunMX2::subst( int option, const KUrl &url, QStringList &ret )
00280 {
00281    switch( option ) {
00282    case 'u':
00283       ret << ((url.isLocalFile() && url.fragment().isNull() && url.encodedQuery().isNull()) ?
00284                  url.toLocalFile()  : url.url());
00285       break;
00286    case 'd':
00287       ret << url.directory();
00288       break;
00289    case 'f':
00290       ret << url.path();
00291       break;
00292    case 'n':
00293       ret << url.fileName();
00294       break;
00295    case 'v':
00296       if (url.isLocalFile() && QFile::exists( url.path() ) )
00297           ret << KDesktopFile( url.path() ).desktopGroup().readEntry( "Dev" );
00298       break;
00299    }
00300    return;
00301 }
00302 
00303 int
00304 KRunMX2::expandEscapedMacro( const QString &str, int pos, QStringList &ret )
00305 {
00306    uint option = str[pos + 1].unicode();
00307    switch( option ) {
00308    case 'f':
00309    case 'u':
00310    case 'n':
00311    case 'd':
00312    case 'v':
00313       if( urls.isEmpty() ) {
00314          if (!ignFile)
00315             kDebug() << "No URLs supplied to single-URL service" << str;
00316       } else if( urls.count() > 1 )
00317           kWarning() << urls.count() << "URLs supplied to single-URL service" << str;
00318       else
00319          subst( option, urls.first(), ret );
00320       break;
00321    case 'F':
00322    case 'U':
00323    case 'N':
00324    case 'D':
00325       option += 'a' - 'A';
00326       for( KUrl::List::ConstIterator it = urls.begin(); it != urls.end(); ++it )
00327          subst( option, *it, ret );
00328       break;
00329    case '%':
00330       ret = QStringList(QLatin1String("%"));
00331       break;
00332    default:
00333       return -2; // subst with same and skip
00334    }
00335    return 2;
00336 }
00337 
00338 QStringList KRun::processDesktopExec(const KService &_service, const KUrl::List& _urls, bool tempFiles, const QString& suggestedFileName)
00339 {
00340   QString exec = _service.exec();
00341   if ( exec.isEmpty() ) {
00342       kWarning() << "KRun: no Exec field in `" << _service.entryPath() << "' !";
00343       return QStringList();
00344   }
00345 
00346   QStringList result;
00347   bool appHasTempFileOption;
00348 
00349   KRunMX1 mx1( _service );
00350   KRunMX2 mx2( _urls );
00351 
00352   if( !mx1.expandMacrosShellQuote( exec ) ) { // Error in shell syntax
00353     kWarning() << "KRun: syntax error in command" << _service.exec() << ", service" << _service.name();
00354     return QStringList();
00355   }
00356 
00357   // FIXME: the current way of invoking kioexec disables term and su use
00358 
00359   // Check if we need "tempexec" (kioexec in fact)
00360   appHasTempFileOption = tempFiles && _service.property("X-KDE-HasTempFileOption").toBool();
00361   if( tempFiles && !appHasTempFileOption && _urls.size() ) {
00362     const QString kioexec = KStandardDirs::findExe("kioexec");
00363     Q_ASSERT(!kioexec.isEmpty());
00364     result << kioexec << "--tempfiles" << exec;
00365     if ( !suggestedFileName.isEmpty() ) {
00366         result << "--suggestedfilename";
00367         result << suggestedFileName;
00368     }
00369     result += _urls.toStringList();
00370     return result;
00371   }
00372 
00373   // Check if we need kioexec
00374   if( !mx1.hasUrls ) {
00375     for( KUrl::List::ConstIterator it = _urls.begin(); it != _urls.end(); ++it )
00376       if ( !(*it).isLocalFile() && !KProtocolInfo::isHelperProtocol(*it) ) {
00377         // We need to run the app through kioexec
00378         const QString kioexec = KStandardDirs::findExe("kioexec");
00379         Q_ASSERT(!kioexec.isEmpty());
00380         result << kioexec;
00381         if ( tempFiles )
00382             result << "--tempfiles";
00383         if ( !suggestedFileName.isEmpty() ) {
00384             result << "--suggestedfilename";
00385             result << suggestedFileName;
00386         }
00387         result << exec;
00388         result += _urls.toStringList();
00389         return result;
00390       }
00391   }
00392 
00393   if ( appHasTempFileOption )
00394       exec += " --tempfile";
00395 
00396   // Did the user forget to append something like '%f'?
00397   // If so, then assume that '%f' is the right choice => the application
00398   // accepts only local files.
00399   if( !mx1.hasSpec ) {
00400     exec += " %f";
00401     mx2.ignFile = true;
00402   }
00403 
00404   mx2.expandMacrosShellQuote( exec ); // syntax was already checked, so don't check return value
00405 
00406 /*
00407  1 = need_shell, 2 = terminal, 4 = su
00408 
00409  0                                                           << split(cmd)
00410  1                                                           << "sh" << "-c" << cmd
00411  2 << split(term) << "-e"                                    << split(cmd)
00412  3 << split(term) << "-e"                                    << "sh" << "-c" << cmd
00413 
00414  4                        << "kdesu" << "-u" << user << "-c" << cmd
00415  5                        << "kdesu" << "-u" << user << "-c" << ("sh -c " + quote(cmd))
00416  6 << split(term) << "-e" << "su"            << user << "-c" << cmd
00417  7 << split(term) << "-e" << "su"            << user << "-c" << ("sh -c " + quote(cmd))
00418 
00419  "sh -c" is needed in the "su" case, too, as su uses the user's login shell, not sh.
00420  this could be optimized with the -s switch of some su versions (e.g., debian linux).
00421 */
00422 
00423   if (_service.terminal()) {
00424     KConfigGroup cg(KGlobal::config(), "General");
00425     QString terminal = cg.readPathEntry("TerminalApplication", "konsole");
00426     if (terminal == "konsole")
00427       terminal += " -caption=%c %i %m";
00428     terminal += ' ';
00429     terminal += _service.terminalOptions();
00430     if( !mx1.expandMacrosShellQuote( terminal ) ) {
00431       kWarning() << "KRun: syntax error in command" << terminal << ", service" << _service.name();
00432       return QStringList();
00433     }
00434     mx2.expandMacrosShellQuote( terminal );
00435     result = KShell::splitArgs( terminal ); // assuming that the term spec never needs a shell!
00436     result << "-e";
00437   }
00438 
00439   KShell::Errors err;
00440   QStringList execlist = KShell::splitArgs(exec, KShell::AbortOnMeta | KShell::TildeExpand, &err);
00441   if (err == KShell::NoError && !execlist.isEmpty()) { // mx1 checked for syntax errors already
00442     // Resolve the executable to ensure that helpers in lib/kde4/libexec/ are found.
00443     // Too bad for commands that need a shell - they must reside in $PATH.
00444     const QString exePath = KStandardDirs::findExe(execlist[0]);
00445     if (!exePath.isEmpty())
00446       execlist[0] = exePath;
00447   }
00448   if (_service.substituteUid()) {
00449     if (_service.terminal())
00450       result << "su";
00451     else
00452       result << KStandardDirs::findExe("kdesu") << "-u";
00453     result << _service.username() << "-c";
00454     if (err == KShell::FoundMeta)
00455       exec = "/bin/sh -c " + KShell::quoteArg(exec);
00456     else
00457       exec = KShell::joinArgs(execlist);
00458     result << exec;
00459   } else {
00460     if (err == KShell::FoundMeta)
00461       result << "/bin/sh" << "-c" << exec;
00462     else
00463       result += execlist;
00464   }
00465 
00466   return result;
00467 }
00468 
00469 //static
00470 QString KRun::binaryName( const QString & execLine, bool removePath )
00471 {
00472   // Remove parameters and/or trailing spaces.
00473   const QStringList args = KShell::splitArgs( execLine );
00474   for (QStringList::ConstIterator it = args.begin(); it != args.end(); ++it)
00475     if (!(*it).contains('='))
00476       // Remove path if wanted
00477       return removePath ? (*it).mid((*it).lastIndexOf('/') + 1) : *it;
00478   return QString();
00479 }
00480 
00481 static bool runCommandInternal( KProcess* proc, const KService* service, const QString& binName,
00482     const QString &execName, const QString & iconName, QWidget* window, const QByteArray& asn )
00483 {
00484   if( window != NULL )
00485       window = window->topLevelWidget();
00486   if (service && !service->entryPath().isEmpty()
00487       && !KDesktopFile::isAuthorizedDesktopFile( service->entryPath() ))
00488   {
00489      kWarning() << "No authorization to execute " << service->entryPath();
00490      KMessageBox::sorry( window, i18n("You are not authorized to execute this file."));
00491      return false;
00492   }
00493   QString bin = KRun::binaryName( binName, true );
00494 #ifdef Q_WS_X11 // Startup notification doesn't work with QT/E, service isn't needed without Startup notification
00495   bool silent;
00496   QByteArray wmclass;
00497   KStartupInfoId id;
00498   bool startup_notify = ( asn != "0" && KRun::checkStartupNotify( binName, service, &silent, &wmclass ));
00499   if( startup_notify )
00500   {
00501       id.initId( asn );
00502       id.setupStartupEnv();
00503       KStartupInfoData data;
00504       data.setHostname();
00505       data.setBin( bin );
00506       if( !execName.isEmpty())
00507           data.setName( execName );
00508       else if( service && !service->name().isEmpty())
00509           data.setName( service->name());
00510       data.setDescription( i18n( "Launching %1" ,  data.name()));
00511       if( !iconName.isEmpty())
00512           data.setIcon( iconName );
00513       else if( service && !service->icon().isEmpty())
00514           data.setIcon( service->icon());
00515       if( !wmclass.isEmpty())
00516           data.setWMClass( wmclass );
00517       if( silent )
00518           data.setSilent( KStartupInfoData::Yes );
00519       data.setDesktop( KWindowSystem::currentDesktop());
00520       if( window )
00521           data.setLaunchedBy( window->winId());
00522       KStartupInfo::sendStartup( id, data );
00523   }
00524   int pid = KProcessRunner::run( proc, binName, id );
00525   if( startup_notify && pid )
00526   {
00527       KStartupInfoData data;
00528       data.addPid( pid );
00529       KStartupInfo::sendChange( id, data );
00530       KStartupInfo::resetStartupEnv();
00531   }
00532   return pid != 0;
00533 #else
00534   Q_UNUSED( execName );
00535   Q_UNUSED( iconName );
00536   return KProcessRunner::run( proc, bin ) != 0;
00537 #endif
00538 }
00539 
00540 // This code is also used in klauncher.
00541 bool KRun::checkStartupNotify( const QString& /*binName*/, const KService* service, bool* silent_arg, QByteArray* wmclass_arg )
00542 {
00543   bool silent = false;
00544   QByteArray wmclass;
00545   if( service && service->property( "StartupNotify" ).isValid())
00546   {
00547       silent = !service->property( "StartupNotify" ).toBool();
00548       wmclass = service->property( "StartupWMClass" ).toString().toLatin1();
00549   }
00550   else if( service && service->property( "X-KDE-StartupNotify" ).isValid())
00551   {
00552       silent = !service->property( "X-KDE-StartupNotify" ).toBool();
00553       wmclass = service->property( "X-KDE-WMClass" ).toString().toLatin1();
00554   }
00555   else // non-compliant app
00556   {
00557       if( service )
00558       {
00559           if( service->isApplication() )
00560               wmclass = "0"; // doesn't have .desktop entries needed, start as non-compliant
00561           else
00562               return false; // no startup notification at all
00563       }
00564       else
00565       {
00566 #if 0
00567         // Create startup notification even for apps for which there shouldn't be any,
00568         // just without any visual feedback. This will ensure they'll be positioned on the proper
00569         // virtual desktop, and will get user timestamp from the ASN ID.
00570           wmclass = "0";
00571           silent = true;
00572 #else   // That unfortunately doesn't work, when the launched non-compliant application
00573         // launches another one that is compliant and there is any delay inbetween (bnc:#343359)
00574           return false;
00575 #endif
00576       }
00577   }
00578   if( silent_arg != NULL )
00579       *silent_arg = silent;
00580   if( wmclass_arg != NULL )
00581       *wmclass_arg = wmclass;
00582   return true;
00583 }
00584 
00585 static bool runTempService( const KService& _service, const KUrl::List& _urls, QWidget* window,
00586     bool tempFiles, const QString& suggestedFileName, const QByteArray& asn )
00587 {
00588   if (!_urls.isEmpty()) {
00589     kDebug(7010) << "runTempService: first url " << _urls.first().url();
00590   }
00591 
00592   QStringList args;
00593   if ((_urls.count() > 1) && !_service.allowMultipleFiles())
00594   {
00595       // We need to launch the application N times. That sucks.
00596       // We ignore the result for application 2 to N.
00597       // For the first file we launch the application in the
00598       // usual way. The reported result is based on this
00599       // application.
00600       KUrl::List::ConstIterator it = _urls.begin();
00601       while(++it != _urls.end())
00602       {
00603          KUrl::List singleUrl;
00604          singleUrl.append(*it);
00605          runTempService( _service, singleUrl, window, tempFiles, suggestedFileName, "" );
00606       }
00607       KUrl::List singleUrl;
00608       singleUrl.append(_urls.first());
00609       args = KRun::processDesktopExec( _service, singleUrl, tempFiles, suggestedFileName );
00610   }
00611   else
00612   {
00613       args = KRun::processDesktopExec(_service, _urls, tempFiles, suggestedFileName );
00614   }
00615   if (args.isEmpty()) {
00616       KMessageBox::sorry(window, i18n("Error processing Exec field in %1", _service.entryPath()) );
00617       return false;
00618   }
00619   kDebug(7010) << "runTempService: KProcess args=" << args;
00620 
00621   KProcess * proc = new KProcess;
00622   *proc << args;
00623 
00624   if (!_service.path().isEmpty())
00625      proc->setWorkingDirectory(_service.path());
00626 
00627   return runCommandInternal( proc, &_service, KRun::binaryName( _service.exec(), false ),
00628                              _service.name(), _service.icon(), window, asn );
00629 }
00630 
00631 // WARNING: don't call this from processDesktopExec, since klauncher uses that too...
00632 static KUrl::List resolveURLs( const KUrl::List& _urls, const KService& _service )
00633 {
00634   // Check which protocols the application supports.
00635   // This can be a list of actual protocol names, or just KIO for KDE apps.
00636   QStringList supportedProtocols = _service.property("X-KDE-Protocols").toStringList();
00637   KRunMX1 mx1( _service );
00638   QString exec = _service.exec();
00639   if ( mx1.expandMacrosShellQuote( exec ) && !mx1.hasUrls ) {
00640     Q_ASSERT( supportedProtocols.isEmpty() ); // huh? If you support protocols you need %u or %U...
00641   } else {
00642     if ( supportedProtocols.isEmpty() )
00643     {
00644       // compat mode: assume KIO if not set and it's a KDE app
00645       QStringList categories = _service.property("Categories").toStringList();
00646       if ( categories.contains("KDE") )
00647          supportedProtocols.append( "KIO" );
00648       else { // if no KDE app, be a bit over-generic
00649          supportedProtocols.append( "http");
00650          supportedProtocols.append( "ftp");
00651       }
00652     }
00653   }
00654   kDebug(7010) << "supportedProtocols:" << supportedProtocols;
00655 
00656   KUrl::List urls( _urls );
00657   if ( !supportedProtocols.contains( "KIO" ) ) {
00658     for( KUrl::List::Iterator it = urls.begin(); it != urls.end(); ++it ) {
00659       const KUrl url = *it;
00660       bool supported = url.isLocalFile() || supportedProtocols.contains( url.protocol().toLower() );
00661       kDebug(7010) << "Looking at url=" << url << " supported=" << supported;
00662       if ( !supported && KProtocolInfo::protocolClass(url.protocol()) == ":local" )
00663       {
00664         // Maybe we can resolve to a local URL?
00665         KUrl localURL = KIO::NetAccess::mostLocalUrl( url, 0 );
00666         if ( localURL != url ) {
00667           *it = localURL;
00668           kDebug(7010) << "Changed to " << localURL;
00669         }
00670       }
00671     }
00672   }
00673   return urls;
00674 }
00675 
00676 bool KRun::run( const KService& _service, const KUrl::List& _urls, QWidget* window,
00677     bool tempFiles, const QString& suggestedFileName, const QByteArray& asn )
00678 {
00679   if (!_service.entryPath().isEmpty() &&
00680       !KDesktopFile::isAuthorizedDesktopFile( _service.entryPath()))
00681   {
00682      kWarning() << "No authorization to execute " << _service.entryPath();
00683      KMessageBox::sorry( window, i18n("You are not authorized to execute this service.") );
00684      return false;
00685   }
00686 
00687   if ( !tempFiles )
00688   {
00689       // Remember we opened those urls, for the "recent documents" menu in kicker
00690       KUrl::List::ConstIterator it = _urls.begin();
00691       for(; it != _urls.end(); ++it) {
00692           //kDebug(7010) << "KRecentDocument::adding " << (*it).url();
00693           KRecentDocument::add( *it, _service.desktopEntryName() );
00694       }
00695   }
00696 
00697   if ( tempFiles || _service.entryPath().isEmpty() || !suggestedFileName.isEmpty() )
00698   {
00699      return runTempService( _service, _urls, window, tempFiles, suggestedFileName, asn );
00700   }
00701 
00702   kDebug(7010) << "KRun::run " << _service.entryPath();
00703 
00704   if (!_urls.isEmpty()) {
00705     kDebug(7010) << "First url " << _urls.first().url();
00706   }
00707 
00708   // Resolve urls if needed, depending on what the app supports
00709   const KUrl::List urls = resolveURLs( _urls, _service );
00710 
00711   QString error;
00712   int pid = 0;
00713 
00714   QByteArray myasn = asn;
00715   // startServiceByDesktopPath() doesn't take QWidget*, add it to the startup info now
00716   if( window != NULL )
00717   {
00718     if( myasn.isEmpty())
00719         myasn = KStartupInfo::createNewStartupId();
00720     if( myasn != "0" )
00721     {
00722         KStartupInfoId id;
00723         id.initId( myasn );
00724         KStartupInfoData data;
00725         data.setLaunchedBy( window->winId());
00726         KStartupInfo::sendChange( id, data );
00727     }
00728   }
00729 
00730   int i = KToolInvocation::startServiceByDesktopPath(
00731         _service.entryPath(), urls.toStringList(), &error, 0L, &pid, myasn
00732         );
00733 
00734   if (i != 0)
00735   {
00736      kDebug(7010) << error;
00737      KMessageBox::sorry( window, error );
00738      return false;
00739   }
00740 
00741   kDebug(7010) << "startServiceByDesktopPath worked fine";
00742   return true;
00743 }
00744 
00745 
00746 bool KRun::run( const QString& _exec, const KUrl::List& _urls, QWidget* window, const QString& _name,
00747                  const QString& _icon, const QByteArray& asn )
00748 {
00749   KService::Ptr service(new KService(_name, _exec, _icon));
00750 
00751   return run( *service, _urls, window, false, QString(), asn );
00752 }
00753 
00754 bool KRun::runCommand( const QString &cmd, QWidget* window )
00755 {
00756   QString bin = binaryName( cmd, true );
00757   return KRun::runCommand( cmd, bin, bin, window, "" );
00758 }
00759 
00760 bool KRun::runCommand( const QString& cmd, const QString &execName, const QString & iconName, QWidget* window, const QByteArray& asn )
00761 {
00762   kDebug(7010) << "runCommand " << cmd << "," << execName;
00763   KProcess * proc = new KProcess;
00764   proc->setShellCommand( cmd );
00765   QString bin = binaryName( execName, true );
00766   KService::Ptr service = KService::serviceByDesktopName( bin );
00767   return runCommandInternal( proc, service.data(), bin, execName, iconName, window, asn );
00768 }
00769 
00770 KRun::KRun( const KUrl& url, QWidget* window, mode_t mode, bool isLocalFile,
00771             bool showProgressInfo, const QByteArray& asn )
00772      : d(new KRunPrivate(this))
00773 {
00774   d->m_timer.setObjectName( "KRun::timer" );
00775   d->m_timer.setSingleShot( true );
00776   d->init (url, window, mode, isLocalFile, showProgressInfo, asn );
00777 }
00778 
00779 void KRun::KRunPrivate::init ( const KUrl& url, QWidget* window, mode_t mode, bool isLocalFile,
00780                                bool showProgressInfo, const QByteArray& asn )
00781 {
00782   m_bFault = false;
00783   m_bAutoDelete = true;
00784   m_bProgressInfo = showProgressInfo;
00785   m_bFinished = false;
00786   m_job = 0L;
00787   m_strURL = url;
00788   m_bScanFile = false;
00789   m_bIsDirectory = false;
00790   m_bIsLocalFile = isLocalFile;
00791   m_mode = mode;
00792   m_runExecutables = true;
00793   m_window = window;
00794   m_asn = asn;
00795   q->setEnableExternalBrowser(true);
00796 
00797   // Start the timer. This means we will return to the event
00798   // loop and do initialization afterwards.
00799   // Reason: We must complete the constructor before we do anything else.
00800   m_bInit = true;
00801   q->connect( &m_timer, SIGNAL( timeout() ), q, SLOT( slotTimeout() ) );
00802   startTimer();
00803   //kDebug(7010) << "new KRun" << q << url << "timer=" << &m_timer;
00804 
00805   KGlobal::ref();
00806 }
00807 
00808 void KRun::init()
00809 {
00810   kDebug(7010) << "INIT called";
00811   if ( !d->m_strURL.isValid() )
00812   {
00813     // TODO KDE5: call virtual method on error (see BrowserRun::init)
00814     d->m_showingDialog = true;
00815     KMessageBoxWrapper::error( d->m_window, i18n( "Malformed URL\n%1", d->m_strURL.url() ) );
00816     d->m_showingDialog = false;
00817     d->m_bFault = true;
00818     d->m_bFinished = true;
00819     d->startTimer();
00820     return;
00821   }
00822   if ( !KAuthorized::authorizeUrlAction( "open", KUrl(), d->m_strURL) )
00823   {
00824     QString msg = KIO::buildErrorString(KIO::ERR_ACCESS_DENIED, d->m_strURL.prettyUrl());
00825     d->m_showingDialog = true;
00826     KMessageBoxWrapper::error( d->m_window, msg );
00827     d->m_showingDialog = false;
00828     d->m_bFault = true;
00829     d->m_bFinished = true;
00830     d->startTimer();
00831     return;
00832   }
00833 
00834   if ( !d->m_bIsLocalFile && d->m_strURL.isLocalFile() )
00835     d->m_bIsLocalFile = true;
00836 
00837   QString exec;
00838   if (d->m_strURL.protocol().startsWith("http"))
00839   {
00840     exec = d->m_externalBrowser;
00841   }
00842 
00843   if ( d->m_bIsLocalFile )
00844   {
00845     if ( d->m_mode == 0 )
00846     {
00847       KDE_struct_stat buff;
00848       if ( KDE_stat( QFile::encodeName(d->m_strURL.path()), &buff ) == -1 )
00849       {
00850         d->m_showingDialog = true;
00851         KMessageBoxWrapper::error( d->m_window, i18n( "<qt>Unable to run the command specified. The file or folder <b>%1</b> does not exist.</qt>" ,  Qt::escape(d->m_strURL.prettyUrl()) ) );
00852         d->m_showingDialog = false;
00853         d->m_bFault = true;
00854         d->m_bFinished = true;
00855         d->startTimer();
00856         return;
00857       }
00858       d->m_mode = buff.st_mode;
00859     }
00860 
00861     KMimeType::Ptr mime = KMimeType::findByUrl( d->m_strURL, d->m_mode, d->m_bIsLocalFile );
00862     assert( mime );
00863     kDebug(7010) << "MIME TYPE is " << mime->name();
00864     mimeTypeDetermined( mime->name() );
00865     return;
00866   }
00867   else if ( !exec.isEmpty() || KProtocolInfo::isHelperProtocol( d->m_strURL ) ) {
00868     kDebug(7010) << "Helper protocol";
00869 
00870     bool ok = false;
00871     KUrl::List urls;
00872     urls.append( d->m_strURL );
00873     if (exec.isEmpty())
00874     {
00875        exec = KProtocolInfo::exec( d->m_strURL.protocol() );
00876        if (exec.isEmpty())
00877        {
00878           mimeTypeDetermined(KProtocolManager::defaultMimetype(d->m_strURL));
00879           return;
00880        }
00881        run( exec, urls, d->m_window, false, QString(), d->m_asn );
00882        ok = true;
00883     }
00884     else if (exec.startsWith('!'))
00885     {
00886        exec = exec.mid(1); // Literal command
00887        exec += " %u";
00888        run( exec, urls, d->m_window, false, QString(), d->m_asn );
00889        ok = true;
00890     }
00891     else
00892     {
00893        KService::Ptr service = KService::serviceByStorageId( exec );
00894        if (service)
00895        {
00896           run( *service, urls, d->m_window, false, QString(), d->m_asn );
00897           ok = true;
00898        }
00899     }
00900 
00901     if (ok)
00902     {
00903        d->m_bFinished = true;
00904        // will emit the error and autodelete this
00905        d->startTimer();
00906        return;
00907     }
00908   }
00909 
00910   // Did we already get the information that it is a directory ?
00911   if ( S_ISDIR( d->m_mode ) )
00912   {
00913     mimeTypeDetermined( "inode/directory" );
00914     return;
00915   }
00916 
00917   // Let's see whether it is a directory
00918 
00919   if ( !KProtocolManager::supportsListing( d->m_strURL ) )
00920   {
00921     //kDebug(7010) << "Protocol has no support for listing";
00922     // No support for listing => it can't be a directory (example: http)
00923     scanFile();
00924     return;
00925   }
00926 
00927   kDebug(7010) << "Testing directory (stating)";
00928 
00929   // It may be a directory or a file, let's stat
00930   KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
00931   KIO::StatJob *job = KIO::stat( d->m_strURL, KIO::StatJob::SourceSide, 0 /* no details */, flags );
00932   job->ui()->setWindow (d->m_window);
00933   connect( job, SIGNAL( result( KJob * ) ),
00934            this, SLOT( slotStatResult( KJob * ) ) );
00935   d->m_job = job;
00936   kDebug(7010) << " Job " << job << " is about stating " << d->m_strURL.url();
00937 }
00938 
00939 KRun::~KRun()
00940 {
00941     //kDebug(7010) << this;
00942     d->m_timer.stop();
00943     killJob();
00944     KGlobal::deref();
00945     //kDebug(7010) << this << "done";
00946     delete d;
00947 }
00948 
00949 void KRun::scanFile()
00950 {
00951   kDebug(7010) << d->m_strURL;
00952   // First, let's check for well-known extensions
00953   // Not when there is a query in the URL, in any case.
00954   if ( d->m_strURL.query().isEmpty() )
00955   {
00956     KMimeType::Ptr mime = KMimeType::findByUrl( d->m_strURL );
00957     assert( mime );
00958     if ( mime->name() != "application/octet-stream" || d->m_bIsLocalFile )
00959     {
00960       kDebug(7010) << "Scanfile: MIME TYPE is " << mime->name();
00961       mimeTypeDetermined( mime->name() );
00962       return;
00963     }
00964   }
00965 
00966   // No mimetype found, and the URL is not local  (or fast mode not allowed).
00967   // We need to apply the 'KIO' method, i.e. either asking the server or
00968   // getting some data out of the file, to know what mimetype it is.
00969 
00970   if ( !KProtocolManager::supportsReading( d->m_strURL ) )
00971   {
00972     kError(7010) << "#### NO SUPPORT FOR READING!";
00973     d->m_bFault = true;
00974     d->m_bFinished = true;
00975     d->startTimer();
00976     return;
00977   }
00978   kDebug(7010) << this << " Scanning file " << d->m_strURL.url();
00979 
00980   KIO::JobFlags flags = d->m_bProgressInfo ? KIO::DefaultFlags : KIO::HideProgressInfo;
00981   KIO::TransferJob *job = KIO::get( d->m_strURL, KIO::NoReload /*reload*/, flags );
00982   job->ui()->setWindow (d->m_window);
00983   connect(job, SIGNAL( result(KJob *)),
00984           this, SLOT( slotScanFinished(KJob *)));
00985   connect(job, SIGNAL( mimetype(KIO::Job *, const QString &)),
00986           this, SLOT( slotScanMimeType(KIO::Job *, const QString &)));
00987   d->m_job = job;
00988   kDebug(7010) << " Job " << job << " is about getting from " << d->m_strURL.url();
00989 }
00990 
00991 void KRun::slotTimeout()
00992 {
00993   kDebug(7010) << this << " slotTimeout called";
00994   if ( d->m_bInit )
00995   {
00996     d->m_bInit = false;
00997     init();
00998     return;
00999   }
01000 
01001   if ( d->m_bFault ) {
01002       emit error();
01003   }
01004   if ( d->m_bFinished ) {
01005       emit finished();
01006   }
01007   else
01008   {
01009     if ( d->m_bScanFile )
01010     {
01011       d->m_bScanFile = false;
01012       scanFile();
01013       return;
01014     }
01015     else if ( d->m_bIsDirectory )
01016     {
01017       d->m_bIsDirectory = false;
01018       mimeTypeDetermined( "inode/directory" );
01019       return;
01020     }
01021   }
01022 
01023   if ( d->m_bAutoDelete )
01024   {
01025     deleteLater();
01026     return;
01027   }
01028 }
01029 
01030 void KRun::slotStatResult( KJob * job )
01031 {
01032   d->m_job = 0L;
01033   if (job->error())
01034   {
01035     d->m_showingDialog = true;
01036     kError(7010) << this << "ERROR" << job->error() << ' ' << job->errorString();
01037     job->uiDelegate()->showErrorMessage();
01038     //kDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us";
01039     d->m_showingDialog = false;
01040 
01041     d->m_bFault = true;
01042     d->m_bFinished = true;
01043 
01044     // will emit the error and autodelete this
01045     d->startTimer();
01046 
01047   } else {
01048 
01049     kDebug(7010) << "Finished";
01050     if(!qobject_cast<KIO::StatJob*>(job))
01051         kFatal() << "job is a " << typeid(*job).name() << " should be a StatJob";
01052 
01053     const KIO::UDSEntry entry = ((KIO::StatJob*)job)->statResult();
01054     const mode_t mode = entry.numberValue( KIO::UDSEntry::UDS_FILE_TYPE );
01055     if ( S_ISDIR( mode ) )
01056         d->m_bIsDirectory = true; // it's a dir
01057     else
01058         d->m_bScanFile = true; // it's a file
01059 
01060     d->m_localPath = entry.stringValue( KIO::UDSEntry::UDS_LOCAL_PATH );
01061 
01062     // mimetype already known? (e.g. print:/manager)
01063     const QString knownMimeType = entry.stringValue( KIO::UDSEntry::UDS_MIME_TYPE ) ;
01064 
01065     if ( !knownMimeType.isEmpty() )
01066     {
01067         mimeTypeDetermined( knownMimeType );
01068         d->m_bFinished = true;
01069     }
01070 
01071     // We should have found something
01072     assert ( d->m_bScanFile || d->m_bIsDirectory );
01073 
01074     // Start the timer. Once we get the timer event this
01075     // protocol server is back in the pool and we can reuse it.
01076     // This gives better performance than starting a new slave
01077     d->startTimer();
01078   }
01079 }
01080 
01081 void KRun::slotScanMimeType( KIO::Job *, const QString &mimetype )
01082 {
01083   if ( mimetype.isEmpty() )
01084     kWarning(7010) << "MimetypeJob didn't find a mimetype! Probably a kioslave bug.";
01085   mimeTypeDetermined( mimetype );
01086   d->m_job = 0;
01087 }
01088 
01089 void KRun::slotScanFinished( KJob *job )
01090 {
01091   d->m_job = 0;
01092   if (job->error())
01093   {
01094     d->m_showingDialog = true;
01095     kError(7010) << this << "ERROR (stat):" << job->error() << ' ' << job->errorString();
01096     job->uiDelegate()->showErrorMessage();
01097     //kDebug(7010) << this << " KRun returning from showErrorDialog, starting timer to delete us";
01098     d->m_showingDialog = false;
01099 
01100     d->m_bFault = true;
01101     d->m_bFinished = true;
01102 
01103     // will emit the error and autodelete this
01104     d->startTimer();
01105   }
01106 }
01107 
01108 void KRun::mimeTypeDetermined(const QString& mimeType)
01109 {
01110     // foundMimeType reimplementations might show a dialog box;
01111     // make sure some timer doesn't kill us meanwhile (#137678, #156447)
01112     Q_ASSERT(!d->m_showingDialog);
01113     d->m_showingDialog = true;
01114 
01115     foundMimeType(mimeType);
01116 
01117     d->m_showingDialog = false;
01118 }
01119 
01120 void KRun::foundMimeType( const QString& type )
01121 {
01122   kDebug(7010) << "Resulting mime type is " << type;
01123 
01124 /*
01125   // Automatically unzip stuff
01126 
01127   // Disabled since the new KIO doesn't have filters yet.
01128 
01129   if ( type == "application/x-gzip"  ||
01130        type == "application/x-bzip"  ||
01131        type == "application/x-bzip"  )
01132   {
01133     KUrl::List lst = KUrl::split( m_strURL );
01134     if ( lst.isEmpty() )
01135     {
01136       QString tmp = i18n( "Malformed URL" );
01137       tmp += "\n";
01138       tmp += m_strURL.url();
01139       KMessageBoxWrapper::error( 0L, tmp );
01140       return;
01141     }
01142 
01143     if ( type == "application/x-gzip" )
01144       lst.prepend( KUrl( "gzip:/decompress" ) );
01145     else if ( type == "application/x-bzip" )
01146       lst.prepend( KUrl( "bzip:/decompress" ) );
01147     else if ( type == "application/x-bzip" )
01148       lst.prepend( KUrl( "bzip2:/decompress" ) );
01149     else if ( type == "application/x-tar" )
01150       lst.prepend( KUrl( "tar:/" ) );
01151 
01152     // Move the HTML style reference to the leftmost URL
01153     KUrl::List::Iterator it = lst.begin();
01154     ++it;
01155     (*lst.begin()).setRef( (*it).ref() );
01156     (*it).setRef( QString() );
01157 
01158     // Create the new URL
01159     m_strURL = KUrl::join( lst );
01160 
01161     kDebug(7010) << "Now trying with " << debugString(m_strURL.url());
01162 
01163     killJob();
01164 
01165     // We don't know if this is a file or a directory. Let's test this first.
01166     // (For instance a tar.gz is a directory contained inside a file)
01167     // It may be a directory or a file, let's stat
01168     KIO::StatJob *job = KIO::stat( m_strURL, m_bProgressInfo );
01169     connect( job, SIGNAL( result( KJob * ) ),
01170              this, SLOT( slotStatResult( KJob * ) ) );
01171     m_job = job;
01172 
01173     return;
01174   }
01175 */
01176   KIO::TransferJob *job = qobject_cast<KIO::TransferJob *>( d->m_job );
01177   if ( job )
01178   {
01179      job->putOnHold();
01180      KIO::Scheduler::publishSlaveOnHold();
01181      d->m_job = 0;
01182   }
01183 
01184   Q_ASSERT( !d->m_bFinished );
01185 
01186   KMimeType::Ptr mime = KMimeType::mimeType(type, KMimeType::ResolveAliases);
01187   if ( !mime )
01188       kWarning(7010) << "Unknown mimetype " << type;
01189 
01190   // Suport for preferred service setting, see setPreferredService
01191   if ( !d->m_preferredService.isEmpty() ) {
01192       kDebug(7010) << "Attempting to open with preferred service: " << d->m_preferredService;
01193       KService::Ptr serv = KService::serviceByDesktopName( d->m_preferredService );
01194       if ( serv && serv->hasMimeType( mime.data() ) )
01195       {
01196           KUrl::List lst;
01197           lst.append( d->m_strURL );
01198           d->m_bFinished = KRun::run( *serv, lst, d->m_window, false, QString(), d->m_asn );
01203       }
01204   }
01205 
01206   // Resolve .desktop files from media:/, remote:/, applications:/ etc.
01207   if ( mime && mime->is( "application/x-desktop" ) && !d->m_localPath.isEmpty() )
01208   {
01209     d->m_strURL = KUrl();
01210     d->m_strURL.setPath( d->m_localPath );
01211   }
01212 
01213   if (!d->m_bFinished && KRun::runUrl( d->m_strURL, type, d->m_window, false /*tempfile*/, d->m_runExecutables, d->m_suggestedFileName, d->m_asn )){
01214     d->m_bFinished = true;
01215   }
01216   else{
01217     d->m_bFinished = true;
01218     d->m_bFault = true;
01219   }
01220 
01221   d->startTimer();
01222 }
01223 
01224 void KRun::killJob()
01225 {
01226   if ( d->m_job )
01227   {
01228     kDebug(7010) << this << "m_job=" << d->m_job;
01229     d->m_job->kill();
01230     d->m_job = 0L;
01231   }
01232 }
01233 
01234 void KRun::abort()
01235 {
01236   kDebug(7010) << this << "m_showingDialog=" << d->m_showingDialog;
01237   killJob();
01238   // If we're showing an error message box, the rest will be done
01239   // after closing the msgbox -> don't autodelete nor emit signals now.
01240   if ( d->m_showingDialog )
01241     return;
01242   d->m_bFault = true;
01243   d->m_bFinished = true;
01244   d->m_bInit = false;
01245   d->m_bScanFile = false;
01246 
01247   // will emit the error and autodelete this
01248   d->startTimer();
01249 }
01250 
01251 bool KRun::hasError() const
01252 {
01253     return d->m_bFault;
01254 }
01255 
01256 bool KRun::hasFinished() const
01257 {
01258     return d->m_bFinished;
01259 }
01260 
01261 bool KRun::autoDelete() const
01262 {
01263     return d->m_bAutoDelete;
01264 }
01265 
01266 void KRun::setAutoDelete(bool b)
01267 {
01268     d->m_bAutoDelete = b;
01269 }
01270 
01271 void KRun::setEnableExternalBrowser(bool b)
01272 {
01273    if (b)
01274       d->m_externalBrowser = KConfigGroup(KGlobal::config(), "General").readEntry("BrowserApplication");
01275    else
01276       d->m_externalBrowser.clear();
01277 }
01278 
01279 void KRun::setPreferredService( const QString& desktopEntryName )
01280 {
01281     d->m_preferredService = desktopEntryName;
01282 }
01283 
01284 void KRun::setRunExecutables(bool b)
01285 {
01286     d->m_runExecutables = b;
01287 }
01288 
01289 void KRun::setSuggestedFileName( const QString& fileName )
01290 {
01291     d->m_suggestedFileName = fileName;
01292 }
01293 
01294 QString KRun::suggestedFileName() const
01295 {
01296   return d->m_suggestedFileName;
01297 }
01298 
01299 bool KRun::isExecutable( const QString& serviceType )
01300 {
01301     return ( serviceType == "application/x-desktop" ||
01302              serviceType == "application/x-executable" ||
01303              serviceType == "application/x-ms-dos-executable" ||
01304              serviceType == "application/x-shellscript" );
01305 }
01306 
01307 void KRun::setUrl( const KUrl &url )
01308 {
01309     d->m_strURL = url;
01310 }
01311 
01312 KUrl KRun::url() const
01313 {
01314     return d->m_strURL;
01315 }
01316 
01317 void KRun::setError( bool error )
01318 {
01319     d->m_bFault = error;
01320 }
01321 
01322 void KRun::setProgressInfo( bool progressInfo )
01323 {
01324     d->m_bProgressInfo = progressInfo;
01325 }
01326 
01327 bool KRun::progressInfo() const
01328 {
01329     return d->m_bProgressInfo;
01330 }
01331 
01332 void KRun::setFinished( bool finished )
01333 {
01334     d->m_bFinished = finished;
01335     // TODO d->startTimer(); (and later on remove it from callers...)
01336 }
01337 
01338 void KRun::setJob( KIO::Job *job )
01339 {
01340     d->m_job = job;
01341 }
01342 
01343 KIO::Job* KRun::job()
01344 {
01345     return d->m_job;
01346 }
01347 
01348 QTimer& KRun::timer()
01349 {
01350     return d->m_timer;
01351 }
01352 
01353 void KRun::setDoScanFile( bool scanFile )
01354 {
01355     d->m_bScanFile = scanFile;
01356 }
01357 
01358 bool KRun::doScanFile() const
01359 {
01360     return d->m_bScanFile;
01361 }
01362 
01363 void KRun::setIsDirecory( bool isDirectory )
01364 {
01365     d->m_bIsDirectory = isDirectory;
01366 }
01367 
01368 bool KRun::isDirectory() const
01369 {
01370     return d->m_bIsDirectory;
01371 }
01372 
01373 void KRun::setInitializeNextAction( bool initialize )
01374 {
01375     d->m_bInit = initialize;
01376 }
01377 
01378 bool KRun::initializeNextAction() const
01379 {
01380     return d->m_bInit;
01381 }
01382 
01383 void KRun::setIsLocalFile( bool isLocalFile )
01384 {
01385     d->m_bIsLocalFile = isLocalFile;
01386 }
01387 
01388 bool KRun::isLocalFile() const
01389 {
01390     return d->m_bIsLocalFile;
01391 }
01392 
01393 void KRun::setMode( mode_t mode )
01394 {
01395     d->m_mode = mode;
01396 }
01397 
01398 mode_t KRun::mode() const
01399 {
01400     return d->m_mode;
01401 }
01402 
01403 /****************/
01404 
01405 #ifndef Q_WS_X11
01406 int KProcessRunner::run(KProcess * p, const QString & binName)
01407 {
01408     return (new KProcessRunner(p, binName))->pid();
01409 }
01410 #else
01411 int KProcessRunner::run(KProcess * p, const QString & binName, const KStartupInfoId& id)
01412 {
01413     return (new KProcessRunner(p, binName, id))->pid();
01414 }
01415 #endif
01416 
01417 #ifndef Q_WS_X11
01418 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName)
01419 #else
01420 KProcessRunner::KProcessRunner(KProcess * p, const QString & _binName, const KStartupInfoId& _id) :
01421     id(_id)
01422 #endif
01423 {
01424     process = p;
01425     binName = _binName;
01426     connect(process, SIGNAL(finished(int, QProcess::ExitStatus)),
01427             this, SLOT(slotProcessExited(int, QProcess::ExitStatus)));
01428 
01429     process->start();
01430     if (!process->waitForStarted()) {
01431         slotProcessExited(127, QProcess::CrashExit);
01432     }
01433 }
01434 
01435 KProcessRunner::~KProcessRunner()
01436 {
01437     delete process;
01438 }
01439 
01440 int KProcessRunner::pid() const
01441 {
01442     return process ? process->pid() : 0;
01443 }
01444 
01445 void
01446 KProcessRunner::slotProcessExited(int exitCode, QProcess::ExitStatus exitStatus)
01447 {
01448     kDebug(7010) << "slotProcessExited " << binName;
01449     kDebug(7010) << "normalExit " << (exitStatus == QProcess::NormalExit);
01450     kDebug(7010) << "exitCode " << exitCode;
01451     bool showErr = exitStatus == QProcess::NormalExit
01452                    && (exitCode == 127 || exitCode == 1);
01453     if (!binName.isEmpty() && (showErr || pid() == 0 )) {
01454         // Often we get 1 (zsh, csh) or 127 (ksh, bash) because the binary doesn't exist.
01455         // We can't just rely on that, but it's a good hint.
01456         // Before assuming its really so, we'll try to find the binName
01457         // relatively to current directory,  and then in the PATH.
01458         if (!QFile(binName).exists() && KStandardDirs::findExe(binName).isEmpty()) {
01459             KGlobal::ref();
01460             KMessageBox::sorry(0L, i18n("Could not find the program '%1'", binName));
01461             KGlobal::deref();
01462         }
01463     }
01464 #ifdef Q_WS_X11
01465     if (!id.none()) {
01466         KStartupInfoData data;
01467         data.addPid(pid()); // announce this pid for the startup notification has finished
01468         data.setHostname();
01469         KStartupInfo::sendFinish(id, data);
01470     }
01471 #endif
01472     deleteLater();
01473 }
01474 
01475 #include "krun.moc"
01476 #include "krun_p.moc"

KIO

Skip menu "KIO"
  • Main Page
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

kdelibs

Skip menu "kdelibs"
  • DNSSD
  • Interfaces
  •   KHexEdit
  •   KMediaPlayer
  •   KSpeech
  •   KTextEditor
  • Kate
  • kconf_update
  • KDE3Support
  •   KUnitTest
  • KDECore
  • KDED
  • KDEsu
  • KDEUI
  • KDocTools
  • KFile
  • KHTML
  • KImgIO
  • KInit
  • KIO
  • KIOSlave
  • KJS
  •   KJS-API
  •   WTF
  • kjsembed
  • KNewStuff
  • KParts
  • Kross
  • KUtils
  • Nepomuk
  • Solid
  • Sonnet
  • ThreadWeaver
Generated for kdelibs by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal