• Skip to content
  • Skip to link menu
KDE 3.5 API Reference
  • KDE API Reference
  • @topname@
  • Sitemap
  • Contact Us
 

kio/kio

krun.cpp

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

kio/kio

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

@topname@

Skip menu "@topname@"
  •     kdnssd-avahi
  • arts
  • dcop
  • dnssd
  • interfaces
  •     interface
  •     library
  •   kspeech
  •   ktexteditor
  • kabc
  • kate
  • kcmshell
  • kdecore
  • kded
  • kdefx
  • kdeprint
  • kdesu
  • kdeui
  • kdoctools
  • khtml
  • kimgio
  • kinit
  • kio
  •   bookmarks
  •   httpfilter
  •   kfile
  •   kio
  •   kioexec
  •   kpasswdserver
  •   kssl
  • kioslave
  •   http
  • kjs
  • kmdi
  •   kmdi
  • knewstuff
  • kparts
  • kresources
  • kspell2
  • kunittest
  • kutils
  • kwallet
  • libkmid
  • libkscreensaver
Generated for @topname@ by doxygen 1.5.5
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