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