kio Library: krun.cpp Source File (kio Library)

| # kio Library API Documentation
Overview | Class Hierarchy | Classes | Classes (annotated) | Members | Namespaces | Source Files

# krun.cpp

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

This file is part of the documentation for kio Library Version 3.4.1.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Sat Jun 11 20:24:03 2005 by doxygen 1.4.1 written by Dimitri van Heesch, © 1997-2003