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

kio

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

API Reference

Skip menu "API Reference"
  • dcop
  • DNSSD
  • interfaces
  • Kate
  • kconf_update
  • KDECore
  • KDED
  • kdefx
  • KDEsu
  • kdeui
  • KDocTools
  • KHTML
  • KImgIO
  • KInit
  • kio
  • kioslave
  • KJS
  • KNewStuff
  • KParts
  • KUtils
Generated for API Reference by doxygen 1.5.9
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